001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.io.hfile;
019
020import edu.umd.cs.findbugs.annotations.Nullable;
021import org.apache.hadoop.conf.Configuration;
022import org.apache.hadoop.hbase.CellComparator;
023import org.apache.hadoop.hbase.HConstants;
024import org.apache.hadoop.hbase.InnerStoreCellComparator;
025import org.apache.hadoop.hbase.io.HeapSize;
026import org.apache.hadoop.hbase.io.compress.Compression;
027import org.apache.hadoop.hbase.io.crypto.Encryption;
028import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
029import org.apache.hadoop.hbase.io.encoding.IndexBlockEncoding;
030import org.apache.hadoop.hbase.util.Bytes;
031import org.apache.hadoop.hbase.util.ChecksumType;
032import org.apache.hadoop.hbase.util.ClassSize;
033import org.apache.yetus.audience.InterfaceAudience;
034
035/**
036 * Read-only HFile Context Information. Meta data that is used by HFileWriter/Readers and by
037 * HFileBlocks. Create one using the {@link HFileContextBuilder} (See HFileInfo and the HFile
038 * Trailer class).
039 * @see HFileContextBuilder
040 */
041@InterfaceAudience.Private
042public class HFileContext implements HeapSize, Cloneable {
043  public static final long FIXED_OVERHEAD = ClassSize.estimateBase(HFileContext.class, false);
044
045  private static final int DEFAULT_BYTES_PER_CHECKSUM = 16 * 1024;
046
047  /** Whether checksum is enabled or not **/
048  private boolean usesHBaseChecksum = true;
049  /** Whether mvcc is to be included in the Read/Write **/
050  private boolean includesMvcc = true;
051  /** Whether tags are to be included in the Read/Write **/
052  private boolean includesTags;
053  /** Compression algorithm used **/
054  private Compression.Algorithm compressAlgo = Compression.Algorithm.NONE;
055  /**
056   * Details used by compression algorithm that are more efficiently loaded once and then reused
057   **/
058  @Nullable
059  private Compression.HFileDecompressionContext decompressionContext = null;
060  /** Whether tags to be compressed or not **/
061  private boolean compressTags;
062  /** the checksum type **/
063  private ChecksumType checksumType = ChecksumType.getDefaultChecksumType();
064  /** the number of bytes per checksum value **/
065  private int bytesPerChecksum = DEFAULT_BYTES_PER_CHECKSUM;
066  /** Number of uncompressed bytes we allow per block. */
067  private int blockSize = HConstants.DEFAULT_BLOCKSIZE;
068  private DataBlockEncoding encoding = DataBlockEncoding.NONE;
069  private IndexBlockEncoding indexBlockEncoding = IndexBlockEncoding.NONE;
070  /** Encryption algorithm and key used */
071  private Encryption.Context cryptoContext = Encryption.Context.NONE;
072  private long fileCreateTime;
073  private String hfileName;
074  private byte[] columnFamily;
075  private byte[] tableName;
076  private CellComparator cellComparator;
077
078  // Empty constructor. Go with setters
079  public HFileContext() {
080  }
081
082  /**
083   * Copy constructor
084   */
085  public HFileContext(HFileContext context) {
086    this.usesHBaseChecksum = context.usesHBaseChecksum;
087    this.includesMvcc = context.includesMvcc;
088    this.includesTags = context.includesTags;
089    this.compressAlgo = context.compressAlgo;
090    this.decompressionContext = context.decompressionContext;
091    this.compressTags = context.compressTags;
092    this.checksumType = context.checksumType;
093    this.bytesPerChecksum = context.bytesPerChecksum;
094    this.blockSize = context.blockSize;
095    this.encoding = context.encoding;
096    this.cryptoContext = context.cryptoContext;
097    this.fileCreateTime = context.fileCreateTime;
098    this.hfileName = context.hfileName;
099    this.columnFamily = context.columnFamily;
100    this.tableName = context.tableName;
101    this.cellComparator = context.cellComparator;
102    this.indexBlockEncoding = context.indexBlockEncoding;
103  }
104
105  HFileContext(boolean useHBaseChecksum, boolean includesMvcc, boolean includesTags,
106    Compression.Algorithm compressAlgo, Compression.HFileDecompressionContext decompressionContext,
107    boolean compressTags, ChecksumType checksumType, int bytesPerChecksum, int blockSize,
108    DataBlockEncoding encoding, Encryption.Context cryptoContext, long fileCreateTime,
109    String hfileName, byte[] columnFamily, byte[] tableName, CellComparator cellComparator,
110    IndexBlockEncoding indexBlockEncoding) {
111    this.usesHBaseChecksum = useHBaseChecksum;
112    this.includesMvcc = includesMvcc;
113    this.includesTags = includesTags;
114    this.compressAlgo = compressAlgo;
115    this.decompressionContext = decompressionContext;
116    this.compressTags = compressTags;
117    this.checksumType = checksumType;
118    this.bytesPerChecksum = bytesPerChecksum;
119    this.blockSize = blockSize;
120    if (encoding != null) {
121      this.encoding = encoding;
122    }
123    if (indexBlockEncoding != null) {
124      this.indexBlockEncoding = indexBlockEncoding;
125    }
126    this.cryptoContext = cryptoContext;
127    this.fileCreateTime = fileCreateTime;
128    this.hfileName = hfileName;
129    this.columnFamily = columnFamily;
130    this.tableName = tableName;
131    // If no cellComparator specified, make a guess based off tablename. If hbase:meta, then should
132    // be the meta table comparator. Comparators are per table.
133    this.cellComparator = cellComparator != null ? cellComparator
134      : this.tableName != null
135        ? InnerStoreCellComparator.getInnerStoreCellComparator(this.tableName)
136      : InnerStoreCellComparator.INNER_STORE_COMPARATOR;
137  }
138
139  /** Returns true when on-disk blocks are compressed, and/or encrypted; false otherwise. */
140  public boolean isCompressedOrEncrypted() {
141    Compression.Algorithm compressAlgo = getCompression();
142    boolean compressed = compressAlgo != null && compressAlgo != Compression.Algorithm.NONE;
143
144    Encryption.Context cryptoContext = getEncryptionContext();
145    boolean encrypted = cryptoContext != null && cryptoContext != Encryption.Context.NONE;
146
147    return compressed || encrypted;
148  }
149
150  public Compression.Algorithm getCompression() {
151    return compressAlgo;
152  }
153
154  /**
155   * Get an object that, if non-null, may be cast into a codec-specific type that exposes some
156   * information from the store-file-specific Configuration that is relevant to decompression. For
157   * example, ZSTD tables can have "hbase.io.compress.zstd.dictionary" on their table descriptor,
158   * and decompressions of blocks in that table must use that dictionary. It's cheaper for HBase to
159   * load these settings into an object of their own once and check this upon each block
160   * decompression, than it is to call into {@link Configuration#get(String)} on each block
161   * decompression.
162   */
163  @Nullable
164  public Compression.HFileDecompressionContext getDecompressionContext() {
165    return decompressionContext;
166  }
167
168  public boolean isUseHBaseChecksum() {
169    return usesHBaseChecksum;
170  }
171
172  public boolean isIncludesMvcc() {
173    return includesMvcc;
174  }
175
176  public void setIncludesMvcc(boolean includesMvcc) {
177    this.includesMvcc = includesMvcc;
178  }
179
180  public boolean isIncludesTags() {
181    return includesTags;
182  }
183
184  public void setIncludesTags(boolean includesTags) {
185    this.includesTags = includesTags;
186  }
187
188  public void setFileCreateTime(long fileCreateTime) {
189    this.fileCreateTime = fileCreateTime;
190  }
191
192  public boolean isCompressTags() {
193    return compressTags;
194  }
195
196  public void setCompressTags(boolean compressTags) {
197    this.compressTags = compressTags;
198  }
199
200  public ChecksumType getChecksumType() {
201    return checksumType;
202  }
203
204  public int getBytesPerChecksum() {
205    return bytesPerChecksum;
206  }
207
208  public int getBlocksize() {
209    return blockSize;
210  }
211
212  public long getFileCreateTime() {
213    return fileCreateTime;
214  }
215
216  public DataBlockEncoding getDataBlockEncoding() {
217    return encoding;
218  }
219
220  public IndexBlockEncoding getIndexBlockEncoding() {
221    return indexBlockEncoding;
222  }
223
224  public Encryption.Context getEncryptionContext() {
225    return cryptoContext;
226  }
227
228  public void setEncryptionContext(Encryption.Context cryptoContext) {
229    this.cryptoContext = cryptoContext;
230  }
231
232  public String getHFileName() {
233    return this.hfileName;
234  }
235
236  public byte[] getColumnFamily() {
237    return this.columnFamily;
238  }
239
240  public byte[] getTableName() {
241    return this.tableName;
242  }
243
244  public CellComparator getCellComparator() {
245    return this.cellComparator;
246  }
247
248  /**
249   * HeapSize implementation. NOTE : The heap size should be altered when new state variable are
250   * added.
251   * @return heap size of the HFileContext
252   */
253  @Override
254  public long heapSize() {
255    long size = FIXED_OVERHEAD;
256    if (this.hfileName != null) {
257      size += ClassSize.STRING + this.hfileName.length();
258    }
259    if (this.columnFamily != null) {
260      size += ClassSize.sizeOfByteArray(this.columnFamily.length);
261    }
262    if (this.tableName != null) {
263      size += ClassSize.sizeOfByteArray(this.tableName.length);
264    }
265    if (this.decompressionContext != null) {
266      size += this.decompressionContext.heapSize();
267    }
268    return size;
269  }
270
271  @Override
272  public HFileContext clone() {
273    try {
274      return (HFileContext) super.clone();
275    } catch (CloneNotSupportedException e) {
276      throw new AssertionError(); // Won't happen
277    }
278  }
279
280  @Override
281  public String toString() {
282    StringBuilder sb = new StringBuilder();
283    sb.append("[");
284    sb.append("usesHBaseChecksum=");
285    sb.append(usesHBaseChecksum);
286    sb.append(", checksumType=");
287    sb.append(checksumType);
288    sb.append(", bytesPerChecksum=");
289    sb.append(bytesPerChecksum);
290    sb.append(", blocksize=");
291    sb.append(blockSize);
292    sb.append(", encoding=");
293    sb.append(encoding);
294    sb.append(", indexBlockEncoding=");
295    sb.append(indexBlockEncoding);
296    sb.append(", includesMvcc=");
297    sb.append(includesMvcc);
298    sb.append(", includesTags=");
299    sb.append(includesTags);
300    sb.append(", compressAlgo=");
301    sb.append(compressAlgo);
302    sb.append(", compressTags=");
303    sb.append(compressTags);
304    sb.append(", decompressionContext=");
305    sb.append(decompressionContext);
306    sb.append(", cryptoContext=[");
307    sb.append(cryptoContext);
308    sb.append("]");
309    if (hfileName != null) {
310      sb.append(", name=");
311      sb.append(hfileName);
312    }
313    if (tableName != null) {
314      sb.append(", tableName=");
315      sb.append(Bytes.toStringBinary(tableName));
316    }
317    if (columnFamily != null) {
318      sb.append(", columnFamily=");
319      sb.append(Bytes.toStringBinary(columnFamily));
320    }
321    sb.append(", cellComparator=");
322    sb.append(this.cellComparator);
323    sb.append("]");
324    return sb.toString();
325  }
326}