View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to you under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14   * License for the specific language governing permissions and limitations
15   * under the License.
16   */
17  package org.apache.hadoop.hbase.io.encoding;
18  
19  import java.io.DataInputStream;
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  import java.nio.ByteBuffer;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.hadoop.hbase.Cell;
27  import org.apache.hadoop.hbase.KeyValue;
28  import org.apache.hadoop.hbase.KeyValue.KVComparator;
29  import org.apache.hadoop.hbase.classification.InterfaceAudience;
30  import org.apache.hadoop.hbase.util.ByteBufferUtils;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  /**
34   * Store cells following every row's start offset, so we can binary search to a row's cells.
35   *
36   * Format:
37   * flat cells
38   * integer: number of rows
39   * integer: row0's offset
40   * integer: row1's offset
41   * ....
42   * integer: dataSize
43   *
44  */
45  @InterfaceAudience.Private
46  public class RowIndexCodecV1 extends AbstractDataBlockEncoder {
47  
48    private static class RowIndexEncodingState extends EncodingState {
49      RowIndexEncoderV1 encoder = null;
50    }
51  
52    @Override
53    public void startBlockEncoding(HFileBlockEncodingContext blkEncodingCtx,
54        DataOutputStream out) throws IOException {
55      if (blkEncodingCtx.getClass() != HFileBlockDefaultEncodingContext.class) {
56        throw new IOException(this.getClass().getName() + " only accepts "
57            + HFileBlockDefaultEncodingContext.class.getName() + " as the "
58            + "encoding context.");
59      }
60  
61      HFileBlockDefaultEncodingContext encodingCtx = (HFileBlockDefaultEncodingContext) blkEncodingCtx;
62      encodingCtx.prepareEncoding(out);
63  
64      RowIndexEncoderV1 encoder = new RowIndexEncoderV1(out, encodingCtx);
65      RowIndexEncodingState state = new RowIndexEncodingState();
66      state.encoder = encoder;
67      blkEncodingCtx.setEncodingState(state);
68    }
69  
70    @Override
71    public int encode(Cell cell, HFileBlockEncodingContext encodingCtx,
72        DataOutputStream out) throws IOException {
73      RowIndexEncodingState state = (RowIndexEncodingState) encodingCtx
74          .getEncodingState();
75      RowIndexEncoderV1 encoder = state.encoder;
76      return encoder.write(cell);
77    }
78  
79    @Override
80    public void endBlockEncoding(HFileBlockEncodingContext encodingCtx,
81        DataOutputStream out, byte[] uncompressedBytesWithHeader)
82        throws IOException {
83      RowIndexEncodingState state = (RowIndexEncodingState) encodingCtx
84          .getEncodingState();
85      RowIndexEncoderV1 encoder = state.encoder;
86      encoder.flush();
87      postEncoding(encodingCtx);
88    }
89  
90    @Override
91    public ByteBuffer decodeKeyValues(DataInputStream source,
92        HFileBlockDecodingContext decodingCtx) throws IOException {
93      if (!decodingCtx.getHFileContext().isIncludesTags()) {
94        ByteBuffer sourceAsBuffer = ByteBufferUtils
95            .drainInputStreamToBuffer(source);// waste
96        sourceAsBuffer.mark();
97        sourceAsBuffer.position(sourceAsBuffer.limit() - Bytes.SIZEOF_INT);
98        int onDiskSize = sourceAsBuffer.getInt();
99        sourceAsBuffer.reset();
100       ByteBuffer dup = sourceAsBuffer.duplicate();
101       dup.position(sourceAsBuffer.position());
102       dup.limit(sourceAsBuffer.position() + onDiskSize);
103       return dup.slice();
104     } else {
105       ByteBuffer sourceAsBuffer = ByteBufferUtils
106           .drainInputStreamToBuffer(source);// waste
107       sourceAsBuffer.mark();
108       RowIndexSeekerV1 seeker = new RowIndexSeekerV1(KeyValue.COMPARATOR,
109           decodingCtx);
110       seeker.setCurrentBuffer(sourceAsBuffer);
111       List<ByteBuffer> kvs = new ArrayList<ByteBuffer>();
112       kvs.add(seeker.getKeyValueBuffer());
113       while (seeker.next()) {
114         kvs.add(seeker.getKeyValueBuffer());
115       }
116       int totalLength = 0;
117       for (ByteBuffer buf : kvs) {
118         totalLength += buf.remaining();
119       }
120       byte[] keyValueBytes = new byte[totalLength];
121       ByteBuffer result = ByteBuffer.wrap(keyValueBytes);
122       for (ByteBuffer buf : kvs) {
123         result.put(buf);
124       }
125       return result;
126     }
127   }
128 
129   @Override
130   public ByteBuffer getFirstKeyInBlock(ByteBuffer block) {
131     block.mark();
132     int keyLength = block.getInt();
133     block.getInt();
134     int pos = block.position();
135     block.reset();
136     ByteBuffer dup = block.duplicate();
137     dup.position(pos);
138     dup.limit(pos + keyLength);
139     return dup.slice();
140   }
141 
142   @Override
143   public EncodedSeeker createSeeker(KVComparator comparator,
144       HFileBlockDecodingContext decodingCtx) {
145     return new RowIndexSeekerV1(comparator, decodingCtx);
146   }
147 
148 }