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