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}