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.codec;
019
020import java.io.IOException;
021import java.io.InputStream;
022import java.io.OutputStream;
023import java.nio.ByteBuffer;
024
025import org.apache.hadoop.hbase.Cell;
026import org.apache.hadoop.hbase.HBaseInterfaceAudience;
027import org.apache.hadoop.hbase.KeyValueUtil;
028import org.apache.hadoop.hbase.NoTagsByteBufferKeyValue;
029import org.apache.hadoop.hbase.NoTagsKeyValue;
030import org.apache.hadoop.hbase.nio.ByteBuff;
031import org.apache.hadoop.hbase.util.ByteBufferUtils;
032import org.apache.yetus.audience.InterfaceAudience;
033
034/**
035 * Codec that does KeyValue version 1 serialization.
036 *
037 * <p>Encodes Cell as serialized in KeyValue with total length prefix.
038 * This is how KVs were serialized in Puts, Deletes and Results pre-0.96.  Its what would
039 * happen if you called the Writable#write KeyValue implementation.  This encoder will fail
040 * if the passed Cell is not an old-school pre-0.96 KeyValue.  Does not copy bytes writing.
041 * It just writes them direct to the passed stream.
042 *
043 * <p>If you wrote two KeyValues to this encoder, it would look like this in the stream:
044 * <pre>
045 * length-of-KeyValue1 // A java int with the length of KeyValue1 backing array
046 * KeyValue1 backing array filled with a KeyValue serialized in its particular format
047 * length-of-KeyValue2
048 * KeyValue2 backing array
049 * </pre>
050 */
051@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
052public class KeyValueCodec implements Codec {
053  public static class KeyValueEncoder extends BaseEncoder {
054    public KeyValueEncoder(final OutputStream out) {
055      super(out);
056    }
057
058    @Override
059    public void write(Cell cell) throws IOException {
060      checkFlushed();
061      // Do not write tags over RPC
062      ByteBufferUtils.putInt(this.out, KeyValueUtil.getSerializedSize(cell, false));
063      KeyValueUtil.oswrite(cell, out, false);
064    }
065  }
066
067  public static class KeyValueDecoder extends BaseDecoder {
068    public KeyValueDecoder(final InputStream in) {
069      super(in);
070    }
071
072    @Override
073    protected Cell parseCell() throws IOException {
074      // No tags here
075      return KeyValueUtil.createKeyValueFromInputStream(in, false);
076    }
077  }
078
079  public static class ByteBuffKeyValueDecoder implements Codec.Decoder {
080
081    protected final ByteBuff buf;
082    protected Cell current = null;
083
084    public ByteBuffKeyValueDecoder(ByteBuff buf) {
085      this.buf = buf;
086    }
087
088    @Override
089    public boolean advance() throws IOException {
090      if (!this.buf.hasRemaining()) {
091        return false;
092      }
093      int len = buf.getInt();
094      ByteBuffer bb = buf.asSubByteBuffer(len);
095      if (bb.isDirect()) {
096        this.current = createCell(bb, bb.position(), len);
097      } else {
098        this.current = createCell(bb.array(), bb.arrayOffset() + bb.position(), len);
099      }
100      buf.skip(len);
101      return true;
102    }
103
104    @Override
105    public Cell current() {
106      return this.current;
107    }
108
109    protected Cell createCell(byte[] buf, int offset, int len) {
110      return new NoTagsKeyValue(buf, offset, len);
111    }
112
113    protected Cell createCell(ByteBuffer bb, int pos, int len) {
114      // We know there is not going to be any tags.
115      return new NoTagsByteBufferKeyValue(bb, pos, len);
116    }
117  }
118
119  /**
120   * Implementation depends on {@link InputStream#available()}
121   */
122  @Override
123  public Decoder getDecoder(final InputStream is) {
124    return new KeyValueDecoder(is);
125  }
126
127  @Override
128  public Decoder getDecoder(ByteBuff buf) {
129    return new ByteBuffKeyValueDecoder(buf);
130  }
131
132  @Override
133  public Encoder getEncoder(OutputStream os) {
134    return new KeyValueEncoder(os);
135  }
136}