View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.io.hfile;
19  
20  import java.io.IOException;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.fs.FSDataOutputStream;
27  import org.apache.hadoop.fs.FileSystem;
28  import org.apache.hadoop.fs.Path;
29  import org.apache.hadoop.hbase.Cell;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.KeyValue.KVComparator;
32  import org.apache.hadoop.hbase.io.crypto.Encryption;
33  import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
34  import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo;
35  import org.apache.hadoop.hbase.io.hfile.HFile.Writer;
36  import org.apache.hadoop.hbase.security.EncryptionUtil;
37  import org.apache.hadoop.hbase.security.User;
38  import org.apache.hadoop.hbase.util.Bytes;
39  
40  /**
41   * {@link HFile} writer for version 3.
42   */
43  @InterfaceAudience.Private
44  public class HFileWriterV3 extends HFileWriterV2 {
45  
46    private static final Log LOG = LogFactory.getLog(HFileWriterV3.class);
47  
48    private int maxTagsLength = 0;
49  
50    static class WriterFactoryV3 extends HFile.WriterFactory {
51      WriterFactoryV3(Configuration conf, CacheConfig cacheConf) {
52        super(conf, cacheConf);
53      }
54  
55      @Override
56      public Writer createWriter(FileSystem fs, Path path, FSDataOutputStream ostream,
57          final KVComparator comparator, HFileContext fileContext)
58          throws IOException {
59        return new HFileWriterV3(conf, cacheConf, fs, path, ostream, comparator, fileContext);
60      }
61    }
62  
63    /** Constructor that takes a path, creates and closes the output stream. */
64    public HFileWriterV3(Configuration conf, CacheConfig cacheConf, FileSystem fs, Path path,
65        FSDataOutputStream ostream, final KVComparator comparator,
66        final HFileContext fileContext) throws IOException {
67      super(conf, cacheConf, fs, path, ostream, comparator, fileContext);
68      if (LOG.isTraceEnabled()) {
69        LOG.trace("Writer" + (path != null ? " for " + path : "") +
70          " initialized with cacheConf: " + cacheConf +
71          " comparator: " + comparator.getClass().getSimpleName() +
72          " fileContext: " + fileContext);
73      }
74    }
75  
76    /**
77     * Add key/value to file. Keys must be added in an order that agrees with the
78     * Comparator passed on construction.
79     * 
80     * @param cell
81     *          Cell to add. Cannot be empty nor null.
82     * @throws IOException
83     */
84    @Override
85    public void append(final Cell cell) throws IOException {
86      // Currently get the complete arrays
87      super.append(cell);
88      int tagsLength = cell.getTagsLength();
89      if (tagsLength > this.maxTagsLength) {
90        this.maxTagsLength = tagsLength;
91      }
92    }
93  
94    protected void finishFileInfo() throws IOException {
95      super.finishFileInfo();
96      if (hFileContext.getDataBlockEncoding() == DataBlockEncoding.PREFIX_TREE) {
97        // In case of Prefix Tree encoding, we always write tags information into HFiles even if all
98        // KVs are having no tags.
99        fileInfo.append(FileInfo.MAX_TAGS_LEN, Bytes.toBytes(this.maxTagsLength), false);
100     } else if (hFileContext.isIncludesTags()) {
101       // When tags are not being written in this file, MAX_TAGS_LEN is excluded
102       // from the FileInfo
103       fileInfo.append(FileInfo.MAX_TAGS_LEN, Bytes.toBytes(this.maxTagsLength), false);
104       boolean tagsCompressed = (hFileContext.getDataBlockEncoding() != DataBlockEncoding.NONE)
105         && hFileContext.isCompressTags();
106       fileInfo.append(FileInfo.TAGS_COMPRESSED, Bytes.toBytes(tagsCompressed), false);
107     }
108   }
109 
110   @Override
111   protected int getMajorVersion() {
112     return 3;
113   }
114 
115   @Override
116   protected int getMinorVersion() {
117     return HFileReaderV3.MAX_MINOR_VERSION;
118   }
119 
120   @Override
121   protected void finishClose(FixedFileTrailer trailer) throws IOException {
122     // Write out encryption metadata before finalizing if we have a valid crypto context
123     Encryption.Context cryptoContext = hFileContext.getEncryptionContext();
124     if (cryptoContext != Encryption.Context.NONE) {
125       // Wrap the context's key and write it as the encryption metadata, the wrapper includes
126       // all information needed for decryption
127       trailer.setEncryptionKey(EncryptionUtil.wrapKey(cryptoContext.getConf(),
128         cryptoContext.getConf().get(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY,
129           User.getCurrent().getShortName()),
130         cryptoContext.getKey()));
131     }
132     // Now we can finish the close
133     super.finishClose(trailer);
134   }
135 
136 }