View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
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.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.hadoop.hbase.classification.InterfaceAudience;
31  import org.apache.hadoop.hbase.classification.InterfaceStability;
32  import org.apache.hadoop.hbase.exceptions.DeserializationException;
33  import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
34  import org.apache.hadoop.hbase.io.compress.Compression;
35  import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
36  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
37  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BytesBytesPair;
38  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ColumnFamilySchema;
39  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
40  import org.apache.hadoop.hbase.regionserver.BloomType;
41  import org.apache.hadoop.hbase.util.Bytes;
42  import org.apache.hadoop.hbase.util.PrettyPrinter;
43  import org.apache.hadoop.hbase.util.PrettyPrinter.Unit;
44  import org.apache.hadoop.io.Text;
45  import org.apache.hadoop.io.WritableComparable;
46  
47  import com.google.common.base.Preconditions;
48  import org.apache.hadoop.hbase.util.ByteStringer;
49  
50  /**
51   * An HColumnDescriptor contains information about a column family such as the
52   * number of versions, compression settings, etc.
53   *
54   * It is used as input when creating a table or adding a column.
55   */
56  @InterfaceAudience.Public
57  @InterfaceStability.Evolving
58  public class HColumnDescriptor implements WritableComparable<HColumnDescriptor> {
59    // For future backward compatibility
60  
61    // Version  3 was when column names become byte arrays and when we picked up
62    // Time-to-live feature.  Version 4 was when we moved to byte arrays, HBASE-82.
63    // Version  5 was when bloom filter descriptors were removed.
64    // Version  6 adds metadata as a map where keys and values are byte[].
65    // Version  7 -- add new compression and hfile blocksize to HColumnDescriptor (HBASE-1217)
66    // Version  8 -- reintroduction of bloom filters, changed from boolean to enum
67    // Version  9 -- add data block encoding
68    // Version 10 -- change metadata to standard type.
69    // Version 11 -- add column family level configuration.
70    private static final byte COLUMN_DESCRIPTOR_VERSION = (byte) 11;
71  
72    // These constants are used as FileInfo keys
73    public static final String COMPRESSION = "COMPRESSION";
74    public static final String COMPRESSION_COMPACT = "COMPRESSION_COMPACT";
75    public static final String ENCODE_ON_DISK = // To be removed, it is not used anymore
76        "ENCODE_ON_DISK";
77    public static final String DATA_BLOCK_ENCODING =
78        "DATA_BLOCK_ENCODING";
79    /**
80     * Key for the BLOCKCACHE attribute.
81     * A more exact name would be CACHE_DATA_ON_READ because this flag sets whether or not we
82     * cache DATA blocks.  We always cache INDEX and BLOOM blocks; caching these blocks cannot be
83     * disabled.
84     */
85    public static final String BLOCKCACHE = "BLOCKCACHE";
86    public static final String CACHE_DATA_ON_WRITE = "CACHE_DATA_ON_WRITE";
87    public static final String CACHE_INDEX_ON_WRITE = "CACHE_INDEX_ON_WRITE";
88    public static final String CACHE_BLOOMS_ON_WRITE = "CACHE_BLOOMS_ON_WRITE";
89    public static final String EVICT_BLOCKS_ON_CLOSE = "EVICT_BLOCKS_ON_CLOSE";
90    /**
91     * Key for cache data into L1 if cache is set up with more than one tier.
92     * To set in the shell, do something like this:
93     * <code>hbase(main):003:0&gt; create 't',
94     *    {NAME =&gt; 't', CONFIGURATION =&gt; {CACHE_DATA_IN_L1 =&gt; 'true'}}</code>
95     */
96    public static final String CACHE_DATA_IN_L1 = "CACHE_DATA_IN_L1";
97  
98    /**
99     * Key for the PREFETCH_BLOCKS_ON_OPEN attribute.
100    * If set, all INDEX, BLOOM, and DATA blocks of HFiles belonging to this
101    * family will be loaded into the cache as soon as the file is opened. These
102    * loads will not count as cache misses.
103    */
104   public static final String PREFETCH_BLOCKS_ON_OPEN = "PREFETCH_BLOCKS_ON_OPEN";
105 
106   /**
107    * Size of storefile/hfile 'blocks'.  Default is {@link #DEFAULT_BLOCKSIZE}.
108    * Use smaller block sizes for faster random-access at expense of larger
109    * indices (more memory consumption).
110    */
111   public static final String BLOCKSIZE = "BLOCKSIZE";
112 
113   public static final String LENGTH = "LENGTH";
114   public static final String TTL = "TTL";
115   public static final String BLOOMFILTER = "BLOOMFILTER";
116   public static final String FOREVER = "FOREVER";
117   public static final String REPLICATION_SCOPE = "REPLICATION_SCOPE";
118   public static final byte[] REPLICATION_SCOPE_BYTES = Bytes.toBytes(REPLICATION_SCOPE);
119   public static final String MIN_VERSIONS = "MIN_VERSIONS";
120   public static final String KEEP_DELETED_CELLS = "KEEP_DELETED_CELLS";
121   public static final String COMPRESS_TAGS = "COMPRESS_TAGS";
122 
123   public static final String ENCRYPTION = "ENCRYPTION";
124   public static final String ENCRYPTION_KEY = "ENCRYPTION_KEY";
125 
126   public static final String IS_MOB = "IS_MOB";
127   public static final byte[] IS_MOB_BYTES = Bytes.toBytes(IS_MOB);
128   public static final String MOB_THRESHOLD = "MOB_THRESHOLD";
129   public static final byte[] MOB_THRESHOLD_BYTES = Bytes.toBytes(MOB_THRESHOLD);
130   public static final long DEFAULT_MOB_THRESHOLD = 100 * 1024; // 100k
131 
132   public static final String DFS_REPLICATION = "DFS_REPLICATION";
133   public static final short DEFAULT_DFS_REPLICATION = 0;
134 
135   /**
136    * Default compression type.
137    */
138   public static final String DEFAULT_COMPRESSION =
139     Compression.Algorithm.NONE.getName();
140 
141   /**
142    * Default value of the flag that enables data block encoding on disk, as
143    * opposed to encoding in cache only. We encode blocks everywhere by default,
144    * as long as {@link #DATA_BLOCK_ENCODING} is not NONE.
145    */
146   public static final boolean DEFAULT_ENCODE_ON_DISK = true;
147 
148   /** Default data block encoding algorithm. */
149   public static final String DEFAULT_DATA_BLOCK_ENCODING =
150       DataBlockEncoding.NONE.toString();
151 
152   /**
153    * Default number of versions of a record to keep.
154    */
155   public static final int DEFAULT_VERSIONS = HBaseConfiguration.create().getInt(
156     "hbase.column.max.version", 1);
157 
158   /**
159    * Default is not to keep a minimum of versions.
160    */
161   public static final int DEFAULT_MIN_VERSIONS = 0;
162 
163   /*
164    * Cache here the HCD value.
165    * Question: its OK to cache since when we're reenable, we create a new HCD?
166    */
167   private volatile Integer blocksize = null;
168 
169   /**
170    * Default setting for whether to try and serve this column family from memory or not.
171    */
172   public static final boolean DEFAULT_IN_MEMORY = false;
173 
174   /**
175    * Default setting for preventing deleted from being collected immediately.
176    */
177   public static final KeepDeletedCells DEFAULT_KEEP_DELETED = KeepDeletedCells.FALSE;
178 
179   /**
180    * Default setting for whether to use a block cache or not.
181    */
182   public static final boolean DEFAULT_BLOCKCACHE = true;
183 
184   /**
185    * Default setting for whether to cache data blocks on write if block caching
186    * is enabled.
187    */
188   public static final boolean DEFAULT_CACHE_DATA_ON_WRITE = false;
189 
190   /**
191    * Default setting for whether to cache data blocks in L1 tier.  Only makes sense if more than
192    * one tier in operations: i.e. if we have an L1 and a L2.  This will be the cases if we are
193    * using BucketCache.
194    */
195   public static final boolean DEFAULT_CACHE_DATA_IN_L1 = false;
196 
197   /**
198    * Default setting for whether to cache index blocks on write if block
199    * caching is enabled.
200    */
201   public static final boolean DEFAULT_CACHE_INDEX_ON_WRITE = false;
202 
203   /**
204    * Default size of blocks in files stored to the filesytem (hfiles).
205    */
206   public static final int DEFAULT_BLOCKSIZE = HConstants.DEFAULT_BLOCKSIZE;
207 
208   /**
209    * Default setting for whether or not to use bloomfilters.
210    */
211   public static final String DEFAULT_BLOOMFILTER = BloomType.ROW.toString();
212 
213   /**
214    * Default setting for whether to cache bloom filter blocks on write if block
215    * caching is enabled.
216    */
217   public static final boolean DEFAULT_CACHE_BLOOMS_ON_WRITE = false;
218 
219   /**
220    * Default time to live of cell contents.
221    */
222   public static final int DEFAULT_TTL = HConstants.FOREVER;
223 
224   /**
225    * Default scope.
226    */
227   public static final int DEFAULT_REPLICATION_SCOPE = HConstants.REPLICATION_SCOPE_LOCAL;
228 
229   /**
230    * Default setting for whether to evict cached blocks from the blockcache on
231    * close.
232    */
233   public static final boolean DEFAULT_EVICT_BLOCKS_ON_CLOSE = false;
234 
235   /**
236    * Default compress tags along with any type of DataBlockEncoding.
237    */
238   public static final boolean DEFAULT_COMPRESS_TAGS = true;
239 
240   /*
241    * Default setting for whether to prefetch blocks into the blockcache on open.
242    */
243   public static final boolean DEFAULT_PREFETCH_BLOCKS_ON_OPEN = false;
244 
245   private final static Map<String, String> DEFAULT_VALUES
246     = new HashMap<String, String>();
247   private final static Set<ImmutableBytesWritable> RESERVED_KEYWORDS
248     = new HashSet<ImmutableBytesWritable>();
249   static {
250       DEFAULT_VALUES.put(BLOOMFILTER, DEFAULT_BLOOMFILTER);
251       DEFAULT_VALUES.put(REPLICATION_SCOPE, String.valueOf(DEFAULT_REPLICATION_SCOPE));
252       DEFAULT_VALUES.put(HConstants.VERSIONS, String.valueOf(DEFAULT_VERSIONS));
253       DEFAULT_VALUES.put(MIN_VERSIONS, String.valueOf(DEFAULT_MIN_VERSIONS));
254       DEFAULT_VALUES.put(COMPRESSION, DEFAULT_COMPRESSION);
255       DEFAULT_VALUES.put(TTL, String.valueOf(DEFAULT_TTL));
256       DEFAULT_VALUES.put(BLOCKSIZE, String.valueOf(DEFAULT_BLOCKSIZE));
257       DEFAULT_VALUES.put(HConstants.IN_MEMORY, String.valueOf(DEFAULT_IN_MEMORY));
258       DEFAULT_VALUES.put(BLOCKCACHE, String.valueOf(DEFAULT_BLOCKCACHE));
259       DEFAULT_VALUES.put(KEEP_DELETED_CELLS, String.valueOf(DEFAULT_KEEP_DELETED));
260       DEFAULT_VALUES.put(DATA_BLOCK_ENCODING, String.valueOf(DEFAULT_DATA_BLOCK_ENCODING));
261       DEFAULT_VALUES.put(CACHE_DATA_ON_WRITE, String.valueOf(DEFAULT_CACHE_DATA_ON_WRITE));
262       DEFAULT_VALUES.put(CACHE_DATA_IN_L1, String.valueOf(DEFAULT_CACHE_DATA_IN_L1));
263       DEFAULT_VALUES.put(CACHE_INDEX_ON_WRITE, String.valueOf(DEFAULT_CACHE_INDEX_ON_WRITE));
264       DEFAULT_VALUES.put(CACHE_BLOOMS_ON_WRITE, String.valueOf(DEFAULT_CACHE_BLOOMS_ON_WRITE));
265       DEFAULT_VALUES.put(EVICT_BLOCKS_ON_CLOSE, String.valueOf(DEFAULT_EVICT_BLOCKS_ON_CLOSE));
266       DEFAULT_VALUES.put(PREFETCH_BLOCKS_ON_OPEN, String.valueOf(DEFAULT_PREFETCH_BLOCKS_ON_OPEN));
267       for (String s : DEFAULT_VALUES.keySet()) {
268         RESERVED_KEYWORDS.add(new ImmutableBytesWritable(Bytes.toBytes(s)));
269       }
270       RESERVED_KEYWORDS.add(new ImmutableBytesWritable(Bytes.toBytes(ENCRYPTION)));
271       RESERVED_KEYWORDS.add(new ImmutableBytesWritable(Bytes.toBytes(ENCRYPTION_KEY)));
272       RESERVED_KEYWORDS.add(new ImmutableBytesWritable(IS_MOB_BYTES));
273       RESERVED_KEYWORDS.add(new ImmutableBytesWritable(MOB_THRESHOLD_BYTES));
274   }
275 
276   private static final int UNINITIALIZED = -1;
277 
278   // Column family name
279   private byte [] name;
280 
281   // Column metadata
282   private final Map<ImmutableBytesWritable, ImmutableBytesWritable> values =
283     new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
284 
285   /**
286    * A map which holds the configuration specific to the column family.
287    * The keys of the map have the same names as config keys and override the defaults with
288    * cf-specific settings. Example usage may be for compactions, etc.
289    */
290   private final Map<String, String> configuration = new HashMap<String, String>();
291 
292   /*
293    * Cache the max versions rather than calculate it every time.
294    */
295   private int cachedMaxVersions = UNINITIALIZED;
296 
297   /**
298    * Default constructor.
299    * @deprecated As of release 0.96
300    *             (<a href="https://issues.apache.org/jira/browse/HBASE-5453">HBASE-5453</a>).
301    *             This will be made private in HBase 2.0.0.
302    *             Used by Writables and Writables are going away.
303    */
304   @Deprecated
305   // Make this private rather than remove after deprecation period elapses.  Its needed by pb
306   // deserializations.
307   public HColumnDescriptor() {
308     this.name = null;
309   }
310 
311   /**
312    * Construct a column descriptor specifying only the family name
313    * The other attributes are defaulted.
314    *
315    * @param familyName Column family name. Must be 'printable' -- digit or
316    * letter -- and may not contain a <code>:</code>
317    */
318   public HColumnDescriptor(final String familyName) {
319     this(Bytes.toBytes(familyName));
320   }
321 
322   /**
323    * Construct a column descriptor specifying only the family name
324    * The other attributes are defaulted.
325    *
326    * @param familyName Column family name. Must be 'printable' -- digit or
327    * letter -- and may not contain a <code>:</code>
328    */
329   public HColumnDescriptor(final byte [] familyName) {
330     this (familyName == null || familyName.length <= 0?
331       HConstants.EMPTY_BYTE_ARRAY: familyName, DEFAULT_VERSIONS,
332       DEFAULT_COMPRESSION, DEFAULT_IN_MEMORY, DEFAULT_BLOCKCACHE,
333       DEFAULT_TTL, DEFAULT_BLOOMFILTER);
334   }
335 
336   /**
337    * Constructor.
338    * Makes a deep copy of the supplied descriptor.
339    * Can make a modifiable descriptor from an UnmodifyableHColumnDescriptor.
340    * @param desc The descriptor.
341    */
342   public HColumnDescriptor(HColumnDescriptor desc) {
343     super();
344     this.name = desc.name.clone();
345     for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
346         desc.values.entrySet()) {
347       this.values.put(e.getKey(), e.getValue());
348     }
349     for (Map.Entry<String, String> e : desc.configuration.entrySet()) {
350       this.configuration.put(e.getKey(), e.getValue());
351     }
352     setMaxVersions(desc.getMaxVersions());
353   }
354 
355   /**
356    * Constructor
357    * @param familyName Column family name. Must be 'printable' -- digit or
358    * letter -- and may not contain a <code>:</code>
359    * @param maxVersions Maximum number of versions to keep
360    * @param compression Compression type
361    * @param inMemory If true, column data should be kept in an HRegionServer's
362    * cache
363    * @param blockCacheEnabled If true, MapFile blocks should be cached
364    * @param timeToLive Time-to-live of cell contents, in seconds
365    * (use HConstants.FOREVER for unlimited TTL)
366    * @param bloomFilter Bloom filter type for this column
367    *
368    * @throws IllegalArgumentException if passed a family name that is made of
369    * other than 'word' characters: i.e. <code>[a-zA-Z_0-9]</code> or contains
370    * a <code>:</code>
371    * @throws IllegalArgumentException if the number of versions is &lt;= 0
372    * @deprecated As of release 0.96
373    *             (<a href="https://issues.apache.org/jira/browse/HBASE-">HBASE-</a>).
374    *             This will be removed in HBase 2.0.0.
375    *             Use {@link #HColumnDescriptor(String)} and setters.
376    */
377   @Deprecated
378   public HColumnDescriptor(final byte [] familyName, final int maxVersions,
379       final String compression, final boolean inMemory,
380       final boolean blockCacheEnabled,
381       final int timeToLive, final String bloomFilter) {
382     this(familyName, maxVersions, compression, inMemory, blockCacheEnabled,
383       DEFAULT_BLOCKSIZE, timeToLive, bloomFilter, DEFAULT_REPLICATION_SCOPE);
384   }
385 
386   /**
387    * Constructor
388    * @param familyName Column family name. Must be 'printable' -- digit or
389    * letter -- and may not contain a <code>:</code>
390    * @param maxVersions Maximum number of versions to keep
391    * @param compression Compression type
392    * @param inMemory If true, column data should be kept in an HRegionServer's
393    * cache
394    * @param blockCacheEnabled If true, MapFile blocks should be cached
395    * @param blocksize Block size to use when writing out storefiles.  Use
396    * smaller block sizes for faster random-access at expense of larger indices
397    * (more memory consumption).  Default is usually 64k.
398    * @param timeToLive Time-to-live of cell contents, in seconds
399    * (use HConstants.FOREVER for unlimited TTL)
400    * @param bloomFilter Bloom filter type for this column
401    * @param scope The scope tag for this column
402    *
403    * @throws IllegalArgumentException if passed a family name that is made of
404    * other than 'word' characters: i.e. <code>[a-zA-Z_0-9]</code> or contains
405    * a <code>:</code>
406    * @throws IllegalArgumentException if the number of versions is &lt;= 0
407    * @deprecated As of release 0.96
408    *             (<a href="https://issues.apache.org/jira/browse/HBASE-">HBASE-</a>).
409    *             This will be removed in HBase 2.0.0.
410    *             Use {@link #HColumnDescriptor(String)} and setters.
411    */
412   @Deprecated
413   public HColumnDescriptor(final byte [] familyName, final int maxVersions,
414       final String compression, final boolean inMemory,
415       final boolean blockCacheEnabled, final int blocksize,
416       final int timeToLive, final String bloomFilter, final int scope) {
417     this(familyName, DEFAULT_MIN_VERSIONS, maxVersions, DEFAULT_KEEP_DELETED,
418         compression, DEFAULT_ENCODE_ON_DISK, DEFAULT_DATA_BLOCK_ENCODING,
419         inMemory, blockCacheEnabled, blocksize, timeToLive, bloomFilter,
420         scope);
421   }
422 
423   /**
424    * Constructor
425    * @param familyName Column family name. Must be 'printable' -- digit or
426    * letter -- and may not contain a <code>:</code>
427    * @param minVersions Minimum number of versions to keep
428    * @param maxVersions Maximum number of versions to keep
429    * @param keepDeletedCells Whether to retain deleted cells until they expire
430    *        up to maxVersions versions.
431    * @param compression Compression type
432    * @param encodeOnDisk whether to use the specified data block encoding
433    *        on disk. If false, the encoding will be used in cache only.
434    * @param dataBlockEncoding data block encoding
435    * @param inMemory If true, column data should be kept in an HRegionServer's
436    * cache
437    * @param blockCacheEnabled If true, MapFile blocks should be cached
438    * @param blocksize Block size to use when writing out storefiles.  Use
439    * smaller blocksizes for faster random-access at expense of larger indices
440    * (more memory consumption).  Default is usually 64k.
441    * @param timeToLive Time-to-live of cell contents, in seconds
442    * (use HConstants.FOREVER for unlimited TTL)
443    * @param bloomFilter Bloom filter type for this column
444    * @param scope The scope tag for this column
445    *
446    * @throws IllegalArgumentException if passed a family name that is made of
447    * other than 'word' characters: i.e. <code>[a-zA-Z_0-9]</code> or contains
448    * a <code>:</code>
449    * @throws IllegalArgumentException if the number of versions is &lt;= 0
450    * @deprecated As of release 0.96
451    *             (<a href="https://issues.apache.org/jira/browse/HBASE-">HBASE-</a>).
452    *             This will be removed in HBase 2.0.0.
453    *             Use {@link #HColumnDescriptor(String)} and setters.
454    */
455   @Deprecated
456   public HColumnDescriptor(final byte[] familyName, final int minVersions,
457       final int maxVersions, final KeepDeletedCells keepDeletedCells,
458       final String compression, final boolean encodeOnDisk,
459       final String dataBlockEncoding, final boolean inMemory,
460       final boolean blockCacheEnabled, final int blocksize,
461       final int timeToLive, final String bloomFilter, final int scope) {
462     isLegalFamilyName(familyName);
463     this.name = familyName;
464 
465     if (maxVersions <= 0) {
466       // TODO: Allow maxVersion of 0 to be the way you say "Keep all versions".
467       // Until there is support, consider 0 or < 0 -- a configuration error.
468       throw new IllegalArgumentException("Maximum versions must be positive");
469     }
470 
471     if (minVersions > 0) {
472       if (timeToLive == HConstants.FOREVER) {
473         throw new IllegalArgumentException("Minimum versions requires TTL.");
474       }
475       if (minVersions >= maxVersions) {
476         throw new IllegalArgumentException("Minimum versions must be < "
477             + "maximum versions.");
478       }
479     }
480 
481     setMaxVersions(maxVersions);
482     setMinVersions(minVersions);
483     setKeepDeletedCells(keepDeletedCells);
484     setInMemory(inMemory);
485     setBlockCacheEnabled(blockCacheEnabled);
486     setTimeToLive(timeToLive);
487     setCompressionType(Compression.Algorithm.
488       valueOf(compression.toUpperCase()));
489     setDataBlockEncoding(DataBlockEncoding.
490         valueOf(dataBlockEncoding.toUpperCase()));
491     setBloomFilterType(BloomType.
492       valueOf(bloomFilter.toUpperCase()));
493     setBlocksize(blocksize);
494     setScope(scope);
495   }
496 
497   /**
498    * Constructor
499    * @param familyName Column family name. Must be 'printable' -- digit or
500    * letter -- and may not contain a <code>:<code>
501    * @param minVersions Minimum number of versions to keep
502    * @param maxVersions Maximum number of versions to keep
503    * @param keepDeletedCells Whether to retain deleted cells until they expire
504    *        up to maxVersions versions.
505    * @param compression Compression type
506    * @param encodeOnDisk whether to use the specified data block encoding
507    *        on disk. If false, the encoding will be used in cache only.
508    * @param dataBlockEncoding data block encoding
509    * @param inMemory If true, column data should be kept in an HRegionServer's
510    * cache
511    * @param blockCacheEnabled If true, MapFile blocks should be cached
512    * @param blocksize Block size to use when writing out storefiles.  Use
513    * smaller blocksizes for faster random-access at expense of larger indices
514    * (more memory consumption).  Default is usually 64k.
515    * @param timeToLive Time-to-live of cell contents, in seconds
516    * (use HConstants.FOREVER for unlimited TTL)
517    * @param bloomFilter Bloom filter type for this column
518    * @param scope The scope tag for this column
519    *
520    * @throws IllegalArgumentException if passed a family name that is made of
521    * other than 'word' characters: i.e. <code>[a-zA-Z_0-9]</code> or contains
522    * a <code>:</code>
523    * @throws IllegalArgumentException if the number of versions is &lt;= 0
524    * @deprecated use {@link #HColumnDescriptor(String)} and setters
525    */
526   @Deprecated
527   public HColumnDescriptor(final byte[] familyName, final int minVersions,
528       final int maxVersions, final boolean keepDeletedCells,
529       final String compression, final boolean encodeOnDisk,
530       final String dataBlockEncoding, final boolean inMemory,
531       final boolean blockCacheEnabled, final int blocksize,
532       final int timeToLive, final String bloomFilter, final int scope) {
533     this(familyName, minVersions, maxVersions,
534         keepDeletedCells ? KeepDeletedCells.TRUE : KeepDeletedCells.FALSE,
535         compression, encodeOnDisk, dataBlockEncoding,
536         inMemory, blockCacheEnabled, blocksize, timeToLive, bloomFilter, scope);
537   }
538 
539   /**
540    * @param b Family name.
541    * @return <code>b</code>
542    * @throws IllegalArgumentException If not null and not a legitimate family
543    * name: i.e. 'printable' and ends in a ':' (Null passes are allowed because
544    * <code>b</code> can be null when deserializing).  Cannot start with a '.'
545    * either. Also Family can not be an empty value or equal "recovered.edits".
546    */
547   public static byte [] isLegalFamilyName(final byte [] b) {
548     if (b == null) {
549       return b;
550     }
551     Preconditions.checkArgument(b.length != 0, "Family name can not be empty");
552     if (b[0] == '.') {
553       throw new IllegalArgumentException("Family names cannot start with a " +
554         "period: " + Bytes.toString(b));
555     }
556     for (int i = 0; i < b.length; i++) {
557       if (Character.isISOControl(b[i]) || b[i] == ':' || b[i] == '\\' || b[i] == '/') {
558         throw new IllegalArgumentException("Illegal character <" + b[i] +
559           ">. Family names cannot contain control characters or colons: " +
560           Bytes.toString(b));
561       }
562     }
563     byte[] recoveredEdit = Bytes.toBytes(HConstants.RECOVERED_EDITS_DIR);
564     if (Bytes.equals(recoveredEdit, b)) {
565       throw new IllegalArgumentException("Family name cannot be: " +
566           HConstants.RECOVERED_EDITS_DIR);
567     }
568     return b;
569   }
570 
571   /**
572    * @return Name of this column family
573    */
574   public byte [] getName() {
575     return name;
576   }
577 
578   /**
579    * @return Name of this column family
580    */
581   public String getNameAsString() {
582     return Bytes.toString(this.name);
583   }
584 
585   /**
586    * @param key The key.
587    * @return The value.
588    */
589   public byte[] getValue(byte[] key) {
590     ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key));
591     if (ibw == null)
592       return null;
593     return ibw.get();
594   }
595 
596   /**
597    * @param key The key.
598    * @return The value as a string.
599    */
600   public String getValue(String key) {
601     byte[] value = getValue(Bytes.toBytes(key));
602     if (value == null)
603       return null;
604     return Bytes.toString(value);
605   }
606 
607   /**
608    * @return All values.
609    */
610   public Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues() {
611     // shallow pointer copy
612     return Collections.unmodifiableMap(values);
613   }
614 
615   /**
616    * @param key The key.
617    * @param value The value.
618    * @return this (for chained invocation)
619    */
620   public HColumnDescriptor setValue(byte[] key, byte[] value) {
621     if (Bytes.compareTo(Bytes.toBytes(HConstants.VERSIONS), key) == 0) {
622       cachedMaxVersions = UNINITIALIZED;
623     }
624     values.put(new ImmutableBytesWritable(key),
625       new ImmutableBytesWritable(value));
626     return this;
627   }
628 
629   /**
630    * @param key Key whose key and value we're to remove from HCD parameters.
631    */
632   public void remove(final byte [] key) {
633     values.remove(new ImmutableBytesWritable(key));
634   }
635 
636   /**
637    * @param key The key.
638    * @param value The value.
639    * @return this (for chained invocation)
640    */
641   public HColumnDescriptor setValue(String key, String value) {
642     if (value == null) {
643       remove(Bytes.toBytes(key));
644     } else {
645       setValue(Bytes.toBytes(key), Bytes.toBytes(value));
646     }
647     return this;
648   }
649 
650   /** @return compression type being used for the column family */
651   public Compression.Algorithm getCompression() {
652     String n = getValue(COMPRESSION);
653     if (n == null) {
654       return Compression.Algorithm.NONE;
655     }
656     return Compression.Algorithm.valueOf(n.toUpperCase());
657   }
658 
659   /** @return compression type being used for the column family for major
660       compression */
661   public Compression.Algorithm getCompactionCompression() {
662     String n = getValue(COMPRESSION_COMPACT);
663     if (n == null) {
664       return getCompression();
665     }
666     return Compression.Algorithm.valueOf(n.toUpperCase());
667   }
668 
669   /** @return maximum number of versions */
670   public int getMaxVersions() {
671     if (this.cachedMaxVersions == UNINITIALIZED) {
672       String v = getValue(HConstants.VERSIONS);
673       this.cachedMaxVersions = Integer.parseInt(v);
674     }
675     return this.cachedMaxVersions;
676   }
677 
678   /**
679    * @param maxVersions maximum number of versions
680    * @return this (for chained invocation)
681    */
682   public HColumnDescriptor setMaxVersions(int maxVersions) {
683     if (maxVersions <= 0) {
684       // TODO: Allow maxVersion of 0 to be the way you say "Keep all versions".
685       // Until there is support, consider 0 or < 0 -- a configuration error.
686       throw new IllegalArgumentException("Maximum versions must be positive");
687     }
688     if (maxVersions < this.getMinVersions()) {
689         throw new IllegalArgumentException("Set MaxVersion to " + maxVersions
690             + " while minVersion is " + this.getMinVersions()
691             + ". Maximum versions must be >= minimum versions ");
692     }
693     setValue(HConstants.VERSIONS, Integer.toString(maxVersions));
694     cachedMaxVersions = maxVersions;
695     return this;
696   }
697 
698   /**
699    * Set minimum and maximum versions to keep
700    *
701    * @param minVersions minimal number of versions
702    * @param maxVersions maximum number of versions
703    * @return this (for chained invocation)
704    */
705   public HColumnDescriptor setVersions(int minVersions, int maxVersions) {
706     if (minVersions <= 0) {
707       // TODO: Allow minVersion and maxVersion of 0 to be the way you say "Keep all versions".
708       // Until there is support, consider 0 or < 0 -- a configuration error.
709       throw new IllegalArgumentException("Minimum versions must be positive");
710     }
711 
712     if (maxVersions < minVersions) {
713       throw new IllegalArgumentException("Unable to set MaxVersion to " + maxVersions
714         + " and set MinVersion to " + minVersions
715         + ", as maximum versions must be >= minimum versions.");
716     }
717     setMinVersions(minVersions);
718     setMaxVersions(maxVersions);
719     return this;
720   }
721 
722   /**
723    * @return The storefile/hfile blocksize for this column family.
724    */
725   public synchronized int getBlocksize() {
726     if (this.blocksize == null) {
727       String value = getValue(BLOCKSIZE);
728       this.blocksize = (value != null)?
729         Integer.decode(value): Integer.valueOf(DEFAULT_BLOCKSIZE);
730     }
731     return this.blocksize.intValue();
732   }
733 
734   /**
735    * @param s Blocksize to use when writing out storefiles/hfiles on this
736    * column family.
737    * @return this (for chained invocation)
738    */
739   public HColumnDescriptor setBlocksize(int s) {
740     setValue(BLOCKSIZE, Integer.toString(s));
741     this.blocksize = null;
742     return this;
743   }
744 
745   /**
746    * @return Compression type setting.
747    */
748   public Compression.Algorithm getCompressionType() {
749     return getCompression();
750   }
751 
752   /**
753    * Compression types supported in hbase.
754    * LZO is not bundled as part of the hbase distribution.
755    * See <a href="http://wiki.apache.org/hadoop/UsingLzoCompression">LZO Compression</a>
756    * for how to enable it.
757    * @param type Compression type setting.
758    * @return this (for chained invocation)
759    */
760   public HColumnDescriptor setCompressionType(Compression.Algorithm type) {
761     return setValue(COMPRESSION, type.getName().toUpperCase());
762   }
763 
764   /**
765    * @return data block encoding algorithm used on disk
766    * @deprecated As of release 0.98
767    *             (<a href="https://issues.apache.org/jira/browse/HBASE-9870">HBASE-9870</a>).
768    *             This will be removed in HBase 2.0.0. See {@link #getDataBlockEncoding()}}
769    */
770   @Deprecated
771   public DataBlockEncoding getDataBlockEncodingOnDisk() {
772     return getDataBlockEncoding();
773   }
774 
775   /**
776    * This method does nothing now. Flag ENCODE_ON_DISK is not used
777    * any more. Data blocks have the same encoding in cache as on disk.
778    * @return this (for chained invocation)
779    * @deprecated As of release 0.98
780    *             (<a href="https://issues.apache.org/jira/browse/HBASE-9870">HBASE-9870</a>).
781    *             This will be removed in HBase 2.0.0. This method does nothing now.
782    */
783   @Deprecated
784   public HColumnDescriptor setEncodeOnDisk(boolean encodeOnDisk) {
785     return this;
786   }
787 
788   /**
789    * @return the data block encoding algorithm used in block cache and
790    *         optionally on disk
791    */
792   public DataBlockEncoding getDataBlockEncoding() {
793     String type = getValue(DATA_BLOCK_ENCODING);
794     if (type == null) {
795       type = DEFAULT_DATA_BLOCK_ENCODING;
796     }
797     return DataBlockEncoding.valueOf(type);
798   }
799 
800   /**
801    * Set data block encoding algorithm used in block cache.
802    * @param type What kind of data block encoding will be used.
803    * @return this (for chained invocation)
804    */
805   public HColumnDescriptor setDataBlockEncoding(DataBlockEncoding type) {
806     String name;
807     if (type != null) {
808       name = type.toString();
809     } else {
810       name = DataBlockEncoding.NONE.toString();
811     }
812     return setValue(DATA_BLOCK_ENCODING, name);
813   }
814 
815   /**
816    * Set whether the tags should be compressed along with DataBlockEncoding. When no
817    * DataBlockEncoding is been used, this is having no effect.
818    *
819    * @param compressTags
820    * @return this (for chained invocation)
821    */
822   public HColumnDescriptor setCompressTags(boolean compressTags) {
823     return setValue(COMPRESS_TAGS, String.valueOf(compressTags));
824   }
825 
826   /**
827    * @return Whether KV tags should be compressed along with DataBlockEncoding. When no
828    *         DataBlockEncoding is been used, this is having no effect.
829    * @deprecated As of release 1.0.0
830    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
831    *             This will be removed in HBase 2.0.0. Use {@link #isCompressTags()} instead.
832    */
833   @Deprecated
834   public boolean shouldCompressTags() {
835     String compressTagsStr = getValue(COMPRESS_TAGS);
836     boolean compressTags = DEFAULT_COMPRESS_TAGS;
837     if (compressTagsStr != null) {
838       compressTags = Boolean.valueOf(compressTagsStr);
839     }
840     return compressTags;
841   }
842 
843   /**
844    * @return Whether KV tags should be compressed along with DataBlockEncoding. When no
845    *         DataBlockEncoding is been used, this is having no effect.
846    */
847   public boolean isCompressTags() {
848     String compressTagsStr = getValue(COMPRESS_TAGS);
849     boolean compressTags = DEFAULT_COMPRESS_TAGS;
850     if (compressTagsStr != null) {
851       compressTags = Boolean.valueOf(compressTagsStr);
852     }
853     return compressTags;
854   }
855 
856   /**
857    * @return Compression type setting.
858    */
859   public Compression.Algorithm getCompactionCompressionType() {
860     return getCompactionCompression();
861   }
862 
863   /**
864    * Compression types supported in hbase.
865    * LZO is not bundled as part of the hbase distribution.
866    * See <a href="http://wiki.apache.org/hadoop/UsingLzoCompression">LZO Compression</a>
867    * for how to enable it.
868    * @param type Compression type setting.
869    * @return this (for chained invocation)
870    */
871   public HColumnDescriptor setCompactionCompressionType(
872       Compression.Algorithm type) {
873     return setValue(COMPRESSION_COMPACT, type.getName().toUpperCase());
874   }
875 
876   /**
877    * @return True if we are to favor keeping all values for this column family in the
878    * HRegionServer cache.
879    */
880   public boolean isInMemory() {
881     String value = getValue(HConstants.IN_MEMORY);
882     if (value != null)
883       return Boolean.valueOf(value).booleanValue();
884     return DEFAULT_IN_MEMORY;
885   }
886 
887   /**
888    * @param inMemory True if we are to favor keeping all values for this column family in the
889    * HRegionServer cache
890    * @return this (for chained invocation)
891    */
892   public HColumnDescriptor setInMemory(boolean inMemory) {
893     return setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory));
894   }
895 
896   /**
897    * This method is equivalent of getKeepDeletedCells() in HBase 1.0.
898    * The same name couldn't be used as it would break compatibility with
899    * earlier CDH5.x versions.
900    */
901   public KeepDeletedCells getKeepDeletedCellsAsEnum() {
902     String value = getValue(KEEP_DELETED_CELLS);
903     if (value != null) {
904       // toUpperCase for backwards compatibility
905       return KeepDeletedCells.valueOf(value.toUpperCase());
906     }
907     return DEFAULT_KEEP_DELETED;
908   }
909 
910   /**
911    * If the KeepDeletedCells enum is being used with HColumnDescriptor,
912    * the value returned in case of TTL will be a mere placeholder and the
913    * KeepDeletedCells enum will be used for internal purposes.
914    * @deprecated use {@link #getKeepDeletedCellsAsEnum()} instead.
915    */
916   @Deprecated
917   public boolean getKeepDeletedCells() {
918     String value = getValue(KEEP_DELETED_CELLS);
919     if (value != null) {
920       KeepDeletedCells kdc = KeepDeletedCells.valueOf(value);
921       switch (kdc) {
922         case TRUE:
923         case TTL:
924           return true;
925         case FALSE:
926           return false;
927         default:
928           throw new IllegalStateException("The value " + kdc + " is not a valid code");
929       }
930     }
931     return Boolean.valueOf(DEFAULT_KEEP_DELETED.toString());
932   }
933 
934   /**
935    * @param keepDeletedCells True if deleted rows should not be collected
936    * immediately.
937    * @return this (for chained invocation)
938    * @deprecated As of release 1.0.0
939    *             (<a href="https://issues.apache.org/jira/browse/HBASE-12363">HBASE-12363</a>).
940    *             This will be removed in HBase 2.0.0.
941    *             Use {@link #setKeepDeletedCells(KeepDeletedCells)}.
942    */
943   @Deprecated
944   public HColumnDescriptor setKeepDeletedCells(boolean keepDeletedCells) {
945     return setValue(KEEP_DELETED_CELLS, (keepDeletedCells ? KeepDeletedCells.TRUE
946         : KeepDeletedCells.FALSE).toString());
947   }
948 
949   /**
950    * @param keepDeletedCells True if deleted rows should not be collected
951    * immediately.
952    * @return this (for chained invocation)
953    */
954   public HColumnDescriptor setKeepDeletedCells(KeepDeletedCells keepDeletedCells) {
955     return setValue(KEEP_DELETED_CELLS, keepDeletedCells.toString());
956   }
957 
958   /**
959    * @return Time-to-live of cell contents, in seconds.
960    */
961   public int getTimeToLive() {
962     String value = getValue(TTL);
963     return (value != null)? Integer.parseInt(value): DEFAULT_TTL;
964   }
965 
966   /**
967    * @param timeToLive Time-to-live of cell contents, in seconds.
968    * @return this (for chained invocation)
969    */
970   public HColumnDescriptor setTimeToLive(int timeToLive) {
971     return setValue(TTL, Integer.toString(timeToLive));
972   }
973 
974   /**
975    * @return The minimum number of versions to keep.
976    */
977   public int getMinVersions() {
978     String value = getValue(MIN_VERSIONS);
979     return (value != null)? Integer.parseInt(value): 0;
980   }
981 
982   /**
983    * @param minVersions The minimum number of versions to keep.
984    * (used when timeToLive is set)
985    * @return this (for chained invocation)
986    */
987   public HColumnDescriptor setMinVersions(int minVersions) {
988     return setValue(MIN_VERSIONS, Integer.toString(minVersions));
989   }
990 
991   /**
992    * @return True if hfile DATA type blocks should be cached (You cannot disable caching of INDEX
993    * and BLOOM type blocks).
994    */
995   public boolean isBlockCacheEnabled() {
996     String value = getValue(BLOCKCACHE);
997     if (value != null)
998       return Boolean.parseBoolean(value);
999     return DEFAULT_BLOCKCACHE;
1000   }
1001 
1002   /**
1003    * @param blockCacheEnabled True if hfile DATA type blocks should be cached (We always cache
1004    * INDEX and BLOOM blocks; you cannot turn this off).
1005    * @return this (for chained invocation)
1006    */
1007   public HColumnDescriptor setBlockCacheEnabled(boolean blockCacheEnabled) {
1008     return setValue(BLOCKCACHE, Boolean.toString(blockCacheEnabled));
1009   }
1010 
1011   /**
1012    * @return bloom filter type used for new StoreFiles in ColumnFamily
1013    */
1014   public BloomType getBloomFilterType() {
1015     String n = getValue(BLOOMFILTER);
1016     if (n == null) {
1017       n = DEFAULT_BLOOMFILTER;
1018     }
1019     return BloomType.valueOf(n.toUpperCase());
1020   }
1021 
1022   /**
1023    * @param bt bloom filter type
1024    * @return this (for chained invocation)
1025    */
1026   public HColumnDescriptor setBloomFilterType(final BloomType bt) {
1027     return setValue(BLOOMFILTER, bt.toString());
1028   }
1029 
1030    /**
1031     * @return the scope tag
1032     */
1033   public int getScope() {
1034     byte[] value = getValue(REPLICATION_SCOPE_BYTES);
1035     if (value != null) {
1036       return Integer.parseInt(Bytes.toString(value));
1037     }
1038     return DEFAULT_REPLICATION_SCOPE;
1039   }
1040 
1041  /**
1042   * @param scope the scope tag
1043   * @return this (for chained invocation)
1044   */
1045   public HColumnDescriptor setScope(int scope) {
1046     return setValue(REPLICATION_SCOPE, Integer.toString(scope));
1047   }
1048 
1049   /**
1050    * @return true if we should cache data blocks on write
1051    * @deprecated As of release 1.0.0
1052    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
1053    *             This will be removed in HBase 2.0.0. Use {@link #isCacheDataOnWrite()}} instead.
1054    */
1055   @Deprecated
1056   public boolean shouldCacheDataOnWrite() {
1057     return setAndGetBoolean(CACHE_DATA_ON_WRITE, DEFAULT_CACHE_DATA_ON_WRITE);
1058   }
1059 
1060   /**
1061    * @return true if we should cache data blocks on write
1062    */
1063   public boolean isCacheDataOnWrite() {
1064     return setAndGetBoolean(CACHE_DATA_ON_WRITE, DEFAULT_CACHE_DATA_ON_WRITE);
1065   }
1066 
1067   /**
1068    * @param value true if we should cache data blocks on write
1069    * @return this (for chained invocation)
1070    */
1071   public HColumnDescriptor setCacheDataOnWrite(boolean value) {
1072     return setValue(CACHE_DATA_ON_WRITE, Boolean.toString(value));
1073   }
1074 
1075   /**
1076    * @return true if we should cache data blocks in the L1 cache (if block cache deploy
1077    * has more than one tier; e.g. we are using CombinedBlockCache).
1078    * @deprecated As of release 1.0.0
1079    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
1080    *             This will be removed in HBase 2.0.0. Use {@link #isCacheDataInL1()}} instead.
1081    */
1082   @Deprecated
1083   public boolean shouldCacheDataInL1() {
1084     return setAndGetBoolean(CACHE_DATA_IN_L1, DEFAULT_CACHE_DATA_IN_L1);
1085   }
1086 
1087   /**
1088    * @return true if we should cache data blocks in the L1 cache (if block cache deploy has more
1089    *         than one tier; e.g. we are using CombinedBlockCache).
1090    */
1091   public boolean isCacheDataInL1() {
1092     return setAndGetBoolean(CACHE_DATA_IN_L1, DEFAULT_CACHE_DATA_IN_L1);
1093   }
1094 
1095   /**
1096    * @param value true if we should cache data blocks in the L1 cache (if block cache deploy
1097    * has more than one tier; e.g. we are using CombinedBlockCache).
1098    * @return this (for chained invocation)
1099    */
1100   public HColumnDescriptor setCacheDataInL1(boolean value) {
1101     return setValue(CACHE_DATA_IN_L1, Boolean.toString(value));
1102   }
1103 
1104   private boolean setAndGetBoolean(final String key, final boolean defaultSetting) {
1105     String value = getValue(key);
1106     if (value != null) return Boolean.parseBoolean(value);
1107     return defaultSetting;
1108   }
1109 
1110   /**
1111    * @return true if we should cache index blocks on write
1112    * @deprecated As of release 1.0.0
1113    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
1114    *             This will be removed in HBase 2.0.0.
1115    *             Use {@link #isCacheIndexesOnWrite()} instead.
1116    */
1117   @Deprecated
1118   public boolean shouldCacheIndexesOnWrite() {
1119     return setAndGetBoolean(CACHE_INDEX_ON_WRITE, DEFAULT_CACHE_INDEX_ON_WRITE);
1120   }
1121 
1122   /**
1123    * @return true if we should cache index blocks on write
1124    */
1125   public boolean isCacheIndexesOnWrite() {
1126     return setAndGetBoolean(CACHE_INDEX_ON_WRITE, DEFAULT_CACHE_INDEX_ON_WRITE);
1127   }
1128 
1129   /**
1130    * @param value true if we should cache index blocks on write
1131    * @return this (for chained invocation)
1132    */
1133   public HColumnDescriptor setCacheIndexesOnWrite(boolean value) {
1134     return setValue(CACHE_INDEX_ON_WRITE, Boolean.toString(value));
1135   }
1136 
1137   /**
1138    * @return true if we should cache bloomfilter blocks on write
1139    * @deprecated As of release 1.0.0
1140    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
1141    *             This will be removed in HBase 2.0.0.
1142    *             Use {@link #isCacheBloomsOnWrite()}} instead.
1143    */
1144   @Deprecated
1145   public boolean shouldCacheBloomsOnWrite() {
1146     return setAndGetBoolean(CACHE_BLOOMS_ON_WRITE, DEFAULT_CACHE_BLOOMS_ON_WRITE);
1147   }
1148 
1149   /**
1150    * @return true if we should cache bloomfilter blocks on write
1151    */
1152   public boolean isCacheBloomsOnWrite() {
1153     return setAndGetBoolean(CACHE_BLOOMS_ON_WRITE, DEFAULT_CACHE_BLOOMS_ON_WRITE);
1154   }
1155 
1156   /**
1157    * @param value true if we should cache bloomfilter blocks on write
1158    * @return this (for chained invocation)
1159    */
1160   public HColumnDescriptor setCacheBloomsOnWrite(boolean value) {
1161     return setValue(CACHE_BLOOMS_ON_WRITE, Boolean.toString(value));
1162   }
1163 
1164   /**
1165    * @return true if we should evict cached blocks from the blockcache on
1166    * close
1167    * @deprecated As of release 1.0.0
1168    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
1169    *             This will be removed in HBase 2.0.0.
1170    *             Use {@link #isEvictBlocksOnClose()}} instead.
1171    */
1172   @Deprecated
1173   public boolean shouldEvictBlocksOnClose() {
1174     return setAndGetBoolean(EVICT_BLOCKS_ON_CLOSE, DEFAULT_EVICT_BLOCKS_ON_CLOSE);
1175   }
1176 
1177   /**
1178    * @return true if we should evict cached blocks from the blockcache on close
1179    */
1180   public boolean isEvictBlocksOnClose() {
1181     return setAndGetBoolean(EVICT_BLOCKS_ON_CLOSE, DEFAULT_EVICT_BLOCKS_ON_CLOSE);
1182   }
1183 
1184   /**
1185    * @param value true if we should evict cached blocks from the blockcache on
1186    * close
1187    * @return this (for chained invocation)
1188    */
1189   public HColumnDescriptor setEvictBlocksOnClose(boolean value) {
1190     return setValue(EVICT_BLOCKS_ON_CLOSE, Boolean.toString(value));
1191   }
1192 
1193   /**
1194    * @return true if we should prefetch blocks into the blockcache on open
1195    * @deprecated As of release 1.0.0
1196    *             (<a href="https://issues.apache.org/jira/browse/HBASE-10870">HBASE-10870</a>).
1197    *             This will be removed in HBase 2.0.0.
1198    *             Use {@link #isPrefetchBlocksOnOpen()}}} instead.
1199    */
1200   @Deprecated
1201   public boolean shouldPrefetchBlocksOnOpen() {
1202     return setAndGetBoolean(PREFETCH_BLOCKS_ON_OPEN, DEFAULT_PREFETCH_BLOCKS_ON_OPEN);
1203   }
1204 
1205   /**
1206    * @return true if we should prefetch blocks into the blockcache on open
1207    */
1208   public boolean isPrefetchBlocksOnOpen() {
1209     return setAndGetBoolean(PREFETCH_BLOCKS_ON_OPEN, DEFAULT_PREFETCH_BLOCKS_ON_OPEN);
1210   }
1211 
1212   /**
1213    * @param value true if we should prefetch blocks into the blockcache on open
1214    * @return this (for chained invocation)
1215    */
1216   public HColumnDescriptor setPrefetchBlocksOnOpen(boolean value) {
1217     return setValue(PREFETCH_BLOCKS_ON_OPEN, Boolean.toString(value));
1218   }
1219 
1220   /**
1221    * @see java.lang.Object#toString()
1222    */
1223   @Override
1224   public String toString() {
1225     StringBuilder s = new StringBuilder();
1226 
1227     s.append('{');
1228     s.append(HConstants.NAME);
1229     s.append(" => '");
1230     s.append(Bytes.toString(name));
1231     s.append("'");
1232     s.append(getValues(true));
1233     s.append('}');
1234     return s.toString();
1235   }
1236 
1237   /**
1238    * @return Column family descriptor with only the customized attributes.
1239    */
1240   public String toStringCustomizedValues() {
1241     StringBuilder s = new StringBuilder();
1242     s.append('{');
1243     s.append(HConstants.NAME);
1244     s.append(" => '");
1245     s.append(Bytes.toString(name));
1246     s.append("'");
1247     s.append(getValues(false));
1248     s.append('}');
1249     return s.toString();
1250   }
1251 
1252   private StringBuilder getValues(boolean printDefaults) {
1253     StringBuilder s = new StringBuilder();
1254 
1255     boolean hasConfigKeys = false;
1256 
1257     // print all reserved keys first
1258     for (ImmutableBytesWritable k : values.keySet()) {
1259       if (!RESERVED_KEYWORDS.contains(k)) {
1260         hasConfigKeys = true;
1261         continue;
1262       }
1263       String key = Bytes.toString(k.get());
1264       String value = Bytes.toStringBinary(values.get(k).get());
1265       if (printDefaults
1266           || !DEFAULT_VALUES.containsKey(key)
1267           || !DEFAULT_VALUES.get(key).equalsIgnoreCase(value)) {
1268         s.append(", ");
1269         s.append(key);
1270         s.append(" => ");
1271         s.append('\'').append(PrettyPrinter.format(value, getUnit(key))).append('\'');
1272       }
1273     }
1274 
1275     // print all non-reserved, advanced config keys as a separate subset
1276     if (hasConfigKeys) {
1277       s.append(", ");
1278       s.append(HConstants.METADATA).append(" => ");
1279       s.append('{');
1280       boolean printComma = false;
1281       for (ImmutableBytesWritable k : values.keySet()) {
1282         if (RESERVED_KEYWORDS.contains(k)) {
1283           continue;
1284         }
1285         String key = Bytes.toString(k.get());
1286         String value = Bytes.toStringBinary(values.get(k).get());
1287         if (printComma) {
1288           s.append(", ");
1289         }
1290         printComma = true;
1291         s.append('\'').append(key).append('\'');
1292         s.append(" => ");
1293         s.append('\'').append(PrettyPrinter.format(value, getUnit(key))).append('\'');
1294       }
1295       s.append('}');
1296     }
1297 
1298     if (!configuration.isEmpty()) {
1299       s.append(", ");
1300       s.append(HConstants.CONFIGURATION).append(" => ");
1301       s.append('{');
1302       boolean printCommaForConfiguration = false;
1303       for (Map.Entry<String, String> e : configuration.entrySet()) {
1304         if (printCommaForConfiguration) s.append(", ");
1305         printCommaForConfiguration = true;
1306         s.append('\'').append(e.getKey()).append('\'');
1307         s.append(" => ");
1308         s.append('\'').append(PrettyPrinter.format(e.getValue(), getUnit(e.getKey()))).append('\'');
1309       }
1310       s.append("}");
1311     }
1312     return s;
1313   }
1314 
1315   public static Unit getUnit(String key) {
1316     Unit unit;
1317       /* TTL for now, we can add more as we neeed */
1318     if (key.equals(HColumnDescriptor.TTL)) {
1319       unit = Unit.TIME_INTERVAL;
1320     } else if (key.equals(HColumnDescriptor.MOB_THRESHOLD)) {
1321       unit = Unit.LONG;
1322     } else if (key.equals(HColumnDescriptor.IS_MOB)) {
1323       unit = Unit.BOOLEAN;
1324     } else {
1325       unit = Unit.NONE;
1326     }
1327     return unit;
1328   }
1329 
1330   public static Map<String, String> getDefaultValues() {
1331     return Collections.unmodifiableMap(DEFAULT_VALUES);
1332   }
1333 
1334   /**
1335    * @see java.lang.Object#equals(java.lang.Object)
1336    */
1337   @Override
1338   public boolean equals(Object obj) {
1339     if (this == obj) {
1340       return true;
1341     }
1342     if (obj == null) {
1343       return false;
1344     }
1345     if (!(obj instanceof HColumnDescriptor)) {
1346       return false;
1347     }
1348     return compareTo((HColumnDescriptor)obj) == 0;
1349   }
1350 
1351   /**
1352    * @see java.lang.Object#hashCode()
1353    */
1354   @Override
1355   public int hashCode() {
1356     int result = Bytes.hashCode(this.name);
1357     result ^= Byte.valueOf(COLUMN_DESCRIPTOR_VERSION).hashCode();
1358     result ^= values.hashCode();
1359     result ^= configuration.hashCode();
1360     return result;
1361   }
1362 
1363   /**
1364    * @deprecated Writables are going away.  Use pb {@link #parseFrom(byte[])} instead.
1365    */
1366   @Deprecated
1367   public void readFields(DataInput in) throws IOException {
1368     int version = in.readByte();
1369     if (version < 6) {
1370       if (version <= 2) {
1371         Text t = new Text();
1372         t.readFields(in);
1373         this.name = t.getBytes();
1374 //        if(KeyValue.getFamilyDelimiterIndex(this.name, 0, this.name.length)
1375 //            > 0) {
1376 //          this.name = stripColon(this.name);
1377 //        }
1378       } else {
1379         this.name = Bytes.readByteArray(in);
1380       }
1381       this.values.clear();
1382       setMaxVersions(in.readInt());
1383       int ordinal = in.readInt();
1384       setCompressionType(Compression.Algorithm.values()[ordinal]);
1385       setInMemory(in.readBoolean());
1386       setBloomFilterType(in.readBoolean() ? BloomType.ROW : BloomType.NONE);
1387       if (getBloomFilterType() != BloomType.NONE && version < 5) {
1388         // If a bloomFilter is enabled and the column descriptor is less than
1389         // version 5, we need to skip over it to read the rest of the column
1390         // descriptor. There are no BloomFilterDescriptors written to disk for
1391         // column descriptors with a version number >= 5
1392         throw new UnsupportedClassVersionError(this.getClass().getName() +
1393             " does not support backward compatibility with versions older " +
1394             "than version 5");
1395       }
1396       if (version > 1) {
1397         setBlockCacheEnabled(in.readBoolean());
1398       }
1399       if (version > 2) {
1400        setTimeToLive(in.readInt());
1401       }
1402     } else {
1403       // version 6+
1404       this.name = Bytes.readByteArray(in);
1405       this.values.clear();
1406       int numValues = in.readInt();
1407       for (int i = 0; i < numValues; i++) {
1408         ImmutableBytesWritable key = new ImmutableBytesWritable();
1409         ImmutableBytesWritable value = new ImmutableBytesWritable();
1410         key.readFields(in);
1411         value.readFields(in);
1412 
1413         // in version 8, the BloomFilter setting changed from bool to enum
1414         if (version < 8 && Bytes.toString(key.get()).equals(BLOOMFILTER)) {
1415           value.set(Bytes.toBytes(
1416               Boolean.getBoolean(Bytes.toString(value.get()))
1417                 ? BloomType.ROW.toString()
1418                 : BloomType.NONE.toString()));
1419         }
1420 
1421         values.put(key, value);
1422       }
1423       if (version == 6) {
1424         // Convert old values.
1425         setValue(COMPRESSION, Compression.Algorithm.NONE.getName());
1426       }
1427       String value = getValue(HConstants.VERSIONS);
1428       this.cachedMaxVersions = (value != null)?
1429           Integer.parseInt(value): DEFAULT_VERSIONS;
1430       if (version > 10) {
1431         configuration.clear();
1432         int numConfigs = in.readInt();
1433         for (int i = 0; i < numConfigs; i++) {
1434           ImmutableBytesWritable key = new ImmutableBytesWritable();
1435           ImmutableBytesWritable val = new ImmutableBytesWritable();
1436           key.readFields(in);
1437           val.readFields(in);
1438           configuration.put(
1439             Bytes.toString(key.get(), key.getOffset(), key.getLength()),
1440             Bytes.toString(val.get(), val.getOffset(), val.getLength()));
1441         }
1442       }
1443     }
1444   }
1445 
1446   /**
1447    * @deprecated Writables are going away.  Use {@link #toByteArray()} instead.
1448    */
1449   @Deprecated
1450   public void write(DataOutput out) throws IOException {
1451     out.writeByte(COLUMN_DESCRIPTOR_VERSION);
1452     Bytes.writeByteArray(out, this.name);
1453     out.writeInt(values.size());
1454     for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
1455         values.entrySet()) {
1456       e.getKey().write(out);
1457       e.getValue().write(out);
1458     }
1459     out.writeInt(configuration.size());
1460     for (Map.Entry<String, String> e : configuration.entrySet()) {
1461       new ImmutableBytesWritable(Bytes.toBytes(e.getKey())).write(out);
1462       new ImmutableBytesWritable(Bytes.toBytes(e.getValue())).write(out);
1463     }
1464   }
1465 
1466   // Comparable
1467   @Override
1468   public int compareTo(HColumnDescriptor o) {
1469     int result = Bytes.compareTo(this.name, o.getName());
1470     if (result == 0) {
1471       // punt on comparison for ordering, just calculate difference
1472       result = this.values.hashCode() - o.values.hashCode();
1473       if (result < 0)
1474         result = -1;
1475       else if (result > 0)
1476         result = 1;
1477     }
1478     if (result == 0) {
1479       result = this.configuration.hashCode() - o.configuration.hashCode();
1480       if (result < 0)
1481         result = -1;
1482       else if (result > 0)
1483         result = 1;
1484     }
1485     return result;
1486   }
1487 
1488   /**
1489    * @return This instance serialized with pb with pb magic prefix
1490    * @see #parseFrom(byte[])
1491    */
1492   public byte [] toByteArray() {
1493     return ProtobufUtil.prependPBMagic(convert().toByteArray());
1494   }
1495 
1496   /**
1497    * @param bytes A pb serialized {@link HColumnDescriptor} instance with pb magic prefix
1498    * @return An instance of {@link HColumnDescriptor} made from <code>bytes</code>
1499    * @throws DeserializationException
1500    * @see #toByteArray()
1501    */
1502   public static HColumnDescriptor parseFrom(final byte [] bytes) throws DeserializationException {
1503     if (!ProtobufUtil.isPBMagicPrefix(bytes)) throw new DeserializationException("No magic");
1504     int pblen = ProtobufUtil.lengthOfPBMagic();
1505     ColumnFamilySchema.Builder builder = ColumnFamilySchema.newBuilder();
1506     ColumnFamilySchema cfs = null;
1507     try {
1508       ProtobufUtil.mergeFrom(builder, bytes, pblen, bytes.length - pblen);
1509       cfs = builder.build();
1510     } catch (IOException e) {
1511       throw new DeserializationException(e);
1512     }
1513     return convert(cfs);
1514   }
1515 
1516   /**
1517    * @param cfs
1518    * @return An {@link HColumnDescriptor} made from the passed in <code>cfs</code>
1519    */
1520   public static HColumnDescriptor convert(final ColumnFamilySchema cfs) {
1521     // Use the empty constructor so we preserve the initial values set on construction for things
1522     // like maxVersion.  Otherwise, we pick up wrong values on deserialization which makes for
1523     // unrelated-looking test failures that are hard to trace back to here.
1524     HColumnDescriptor hcd = new HColumnDescriptor();
1525     hcd.name = cfs.getName().toByteArray();
1526     for (BytesBytesPair a: cfs.getAttributesList()) {
1527       hcd.setValue(a.getFirst().toByteArray(), a.getSecond().toByteArray());
1528     }
1529     for (NameStringPair a: cfs.getConfigurationList()) {
1530       hcd.setConfiguration(a.getName(), a.getValue());
1531     }
1532     return hcd;
1533   }
1534 
1535   /**
1536    * @return Convert this instance to a the pb column family type
1537    */
1538   public ColumnFamilySchema convert() {
1539     ColumnFamilySchema.Builder builder = ColumnFamilySchema.newBuilder();
1540     builder.setName(ByteStringer.wrap(getName()));
1541     for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e: this.values.entrySet()) {
1542       BytesBytesPair.Builder aBuilder = BytesBytesPair.newBuilder();
1543       aBuilder.setFirst(ByteStringer.wrap(e.getKey().get()));
1544       aBuilder.setSecond(ByteStringer.wrap(e.getValue().get()));
1545       builder.addAttributes(aBuilder.build());
1546     }
1547     for (Map.Entry<String, String> e : this.configuration.entrySet()) {
1548       NameStringPair.Builder aBuilder = NameStringPair.newBuilder();
1549       aBuilder.setName(e.getKey());
1550       aBuilder.setValue(e.getValue());
1551       builder.addConfiguration(aBuilder.build());
1552     }
1553     return builder.build();
1554   }
1555 
1556   /**
1557    * Getter for accessing the configuration value by key.
1558    */
1559   public String getConfigurationValue(String key) {
1560     return configuration.get(key);
1561   }
1562 
1563   /**
1564    * Getter for fetching an unmodifiable {@link #configuration} map.
1565    */
1566   public Map<String, String> getConfiguration() {
1567     // shallow pointer copy
1568     return Collections.unmodifiableMap(configuration);
1569   }
1570 
1571   /**
1572    * Setter for storing a configuration setting in {@link #configuration} map.
1573    * @param key Config key. Same as XML config key e.g. hbase.something.or.other.
1574    * @param value String value. If null, removes the configuration.
1575    */
1576   public void setConfiguration(String key, String value) {
1577     if (value == null) {
1578       removeConfiguration(key);
1579     } else {
1580       configuration.put(key, value);
1581     }
1582   }
1583 
1584   /**
1585    * Remove a configuration setting represented by the key from the {@link #configuration} map.
1586    */
1587   public void removeConfiguration(final String key) {
1588     configuration.remove(key);
1589   }
1590 
1591   /**
1592    * Return the encryption algorithm in use by this family
1593    */
1594   public String getEncryptionType() {
1595     return getValue(ENCRYPTION);
1596   }
1597 
1598   /**
1599    * Set the encryption algorithm for use with this family
1600    * @param algorithm
1601    */
1602   public HColumnDescriptor setEncryptionType(String algorithm) {
1603     setValue(ENCRYPTION, algorithm);
1604     return this;
1605   }
1606 
1607   /** Return the raw crypto key attribute for the family, or null if not set  */
1608   public byte[] getEncryptionKey() {
1609     return getValue(Bytes.toBytes(ENCRYPTION_KEY));
1610   }
1611 
1612   /** Set the raw crypto key attribute for the family */
1613   public HColumnDescriptor setEncryptionKey(byte[] keyBytes) {
1614     setValue(Bytes.toBytes(ENCRYPTION_KEY), keyBytes);
1615     return this;
1616   }
1617 
1618   /**
1619    * Gets the mob threshold of the family.
1620    * If the size of a cell value is larger than this threshold, it's regarded as a mob.
1621    * The default threshold is 1024*100(100K)B.
1622    * @return The mob threshold.
1623    */
1624   public long getMobThreshold() {
1625     byte[] threshold = getValue(MOB_THRESHOLD_BYTES);
1626     return threshold != null && threshold.length == Bytes.SIZEOF_LONG ? Bytes.toLong(threshold)
1627         : DEFAULT_MOB_THRESHOLD;
1628   }
1629 
1630   /**
1631    * Sets the mob threshold of the family.
1632    * @param threshold The mob threshold.
1633    * @return this (for chained invocation)
1634    */
1635   public HColumnDescriptor setMobThreshold(long threshold) {
1636     setValue(MOB_THRESHOLD_BYTES, Bytes.toBytes(threshold));
1637     return this;
1638   }
1639 
1640   /**
1641    * Gets whether the mob is enabled for the family.
1642    * @return True if the mob is enabled for the family.
1643    */
1644   public boolean isMobEnabled() {
1645     byte[] isMobEnabled = getValue(IS_MOB_BYTES);
1646     return isMobEnabled != null && isMobEnabled.length == Bytes.SIZEOF_BOOLEAN
1647         && Bytes.toBoolean(isMobEnabled);
1648   }
1649 
1650   /**
1651    * Enables the mob for the family.
1652    * @param isMobEnabled Whether to enable the mob for the family.
1653    * @return this (for chained invocation)
1654    */
1655   public HColumnDescriptor setMobEnabled(boolean isMobEnabled) {
1656     setValue(IS_MOB_BYTES, Bytes.toBytes(isMobEnabled));
1657     return this;
1658   }
1659 
1660   /**
1661    * @return replication factor set for this CF or {@link #DEFAULT_DFS_REPLICATION} if not set.
1662    *         <p>
1663    *         {@link #DEFAULT_DFS_REPLICATION} value indicates that user has explicitly not set any
1664    *         block replication factor for this CF, hence use the default replication factor set in
1665    *         the file system.
1666    */
1667   public short getDFSReplication() {
1668     String rf = getValue(DFS_REPLICATION);
1669     return rf == null ? DEFAULT_DFS_REPLICATION : Short.parseShort(rf);
1670   }
1671 
1672   /**
1673    * Set the replication factor to hfile(s) belonging to this family
1674    * @param replication number of replicas the blocks(s) belonging to this CF should have, or
1675    *          {@link #DEFAULT_DFS_REPLICATION} for the default replication factor set in the
1676    *          filesystem
1677    * @return this (for chained invocation)
1678    */
1679   public HColumnDescriptor setDFSReplication(short replication) {
1680     if (replication < 1 && replication != DEFAULT_DFS_REPLICATION) {
1681       throw new IllegalArgumentException(
1682           "DFS replication factor cannot be less than 1 if explictly set.");
1683     }
1684     setValue(DFS_REPLICATION, Short.toString(replication));
1685     return this;
1686   }
1687 }