001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with this 004 * work for additional information regarding copyright ownership. The ASF 005 * licenses this file to you under the Apache License, Version 2.0 (the 006 * "License"); you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017package org.apache.hadoop.hbase.io.encoding; 018 019import java.io.DataInputStream; 020import java.io.IOException; 021import java.io.InputStream; 022import org.apache.commons.io.IOUtils; 023import org.apache.hadoop.hbase.io.ByteBuffInputStream; 024import org.apache.hadoop.hbase.io.TagCompressionContext; 025import org.apache.hadoop.hbase.io.compress.Compression; 026import org.apache.hadoop.hbase.io.crypto.Cipher; 027import org.apache.hadoop.hbase.io.crypto.Decryptor; 028import org.apache.hadoop.hbase.io.crypto.Encryption; 029import org.apache.hadoop.hbase.io.hfile.HFileContext; 030import org.apache.hadoop.hbase.io.util.BlockIOUtils; 031import org.apache.hadoop.hbase.nio.ByteBuff; 032import org.apache.hadoop.hbase.util.Bytes; 033import org.apache.yetus.audience.InterfaceAudience; 034 035/** 036 * A default implementation of {@link HFileBlockDecodingContext}. It assumes the 037 * block data section is compressed as a whole. 038 * 039 * @see HFileBlockDefaultEncodingContext for the default compression context 040 * 041 */ 042@InterfaceAudience.Private 043public class HFileBlockDefaultDecodingContext implements HFileBlockDecodingContext { 044 private final HFileContext fileContext; 045 private TagCompressionContext tagCompressionContext; 046 047 public HFileBlockDefaultDecodingContext(HFileContext fileContext) { 048 this.fileContext = fileContext; 049 } 050 051 @Override 052 public void prepareDecoding(int onDiskSizeWithoutHeader, int uncompressedSizeWithoutHeader, 053 ByteBuff blockBufferWithoutHeader, ByteBuff onDiskBlock) throws IOException { 054 final ByteBuffInputStream byteBuffInputStream = new ByteBuffInputStream(onDiskBlock); 055 InputStream dataInputStream = new DataInputStream(byteBuffInputStream); 056 057 try { 058 Encryption.Context cryptoContext = fileContext.getEncryptionContext(); 059 if (cryptoContext != Encryption.Context.NONE) { 060 061 Cipher cipher = cryptoContext.getCipher(); 062 Decryptor decryptor = cipher.getDecryptor(); 063 decryptor.setKey(cryptoContext.getKey()); 064 065 // Encrypted block format: 066 // +--------------------------+ 067 // | byte iv length | 068 // +--------------------------+ 069 // | iv data ... | 070 // +--------------------------+ 071 // | encrypted block data ... | 072 // +--------------------------+ 073 074 int ivLength = dataInputStream.read(); 075 if (ivLength > 0) { 076 byte[] iv = new byte[ivLength]; 077 IOUtils.readFully(dataInputStream, iv); 078 decryptor.setIv(iv); 079 // All encrypted blocks will have a nonzero IV length. If we see an IV 080 // length of zero, this means the encoding context had 0 bytes of 081 // plaintext to encode. 082 decryptor.reset(); 083 dataInputStream = decryptor.createDecryptionStream(dataInputStream); 084 } 085 onDiskSizeWithoutHeader -= Bytes.SIZEOF_BYTE + ivLength; 086 } 087 088 Compression.Algorithm compression = fileContext.getCompression(); 089 if (compression != Compression.Algorithm.NONE) { 090 Compression.decompress(blockBufferWithoutHeader, dataInputStream, 091 uncompressedSizeWithoutHeader, compression); 092 } else { 093 BlockIOUtils.readFullyWithHeapBuffer(dataInputStream, blockBufferWithoutHeader, 094 onDiskSizeWithoutHeader); 095 } 096 } finally { 097 byteBuffInputStream.close(); 098 dataInputStream.close(); 099 } 100 } 101 102 @Override 103 public HFileContext getHFileContext() { 104 return this.fileContext; 105 } 106 107 public TagCompressionContext getTagCompressionContext() { 108 return tagCompressionContext; 109 } 110 111 public void setTagCompressionContext(TagCompressionContext tagCompressionContext) { 112 this.tagCompressionContext = tagCompressionContext; 113 } 114}