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 */ 018 019package org.apache.hadoop.io; 020 021import java.io.IOException; 022import java.io.DataInput; 023import java.io.DataOutput; 024 025import org.apache.hadoop.classification.InterfaceAudience; 026import org.apache.hadoop.classification.InterfaceStability; 027 028/** 029 * A byte sequence that is usable as a key or value. 030 * It is resizable and distinguishes between the size of the seqeunce and 031 * the current capacity. The hash function is the front of the md5 of the 032 * buffer. The sort order is the same as memcmp. 033 */ 034@InterfaceAudience.Public 035@InterfaceStability.Stable 036public class BytesWritable extends BinaryComparable 037 implements WritableComparable<BinaryComparable> { 038 private static final int LENGTH_BYTES = 4; 039 private static final byte[] EMPTY_BYTES = {}; 040 041 private int size; 042 private byte[] bytes; 043 044 /** 045 * Create a zero-size sequence. 046 */ 047 public BytesWritable() {this(EMPTY_BYTES);} 048 049 /** 050 * Create a BytesWritable using the byte array as the initial value. 051 * @param bytes This array becomes the backing storage for the object. 052 */ 053 public BytesWritable(byte[] bytes) { 054 this(bytes, bytes.length); 055 } 056 057 /** 058 * Create a BytesWritable using the byte array as the initial value 059 * and length as the length. Use this constructor if the array is larger 060 * than the value it represents. 061 * @param bytes This array becomes the backing storage for the object. 062 * @param length The number of bytes to use from array. 063 */ 064 public BytesWritable(byte[] bytes, int length) { 065 this.bytes = bytes; 066 this.size = length; 067 } 068 069 /** 070 * Get a copy of the bytes that is exactly the length of the data. 071 * See {@link #getBytes()} for faster access to the underlying array. 072 */ 073 public byte[] copyBytes() { 074 byte[] result = new byte[size]; 075 System.arraycopy(bytes, 0, result, 0, size); 076 return result; 077 } 078 079 /** 080 * Get the data backing the BytesWritable. Please use {@link #copyBytes()} 081 * if you need the returned array to be precisely the length of the data. 082 * @return The data is only valid between 0 and getLength() - 1. 083 */ 084 public byte[] getBytes() { 085 return bytes; 086 } 087 088 /** 089 * Get the data from the BytesWritable. 090 * @deprecated Use {@link #getBytes()} instead. 091 */ 092 @Deprecated 093 public byte[] get() { 094 return getBytes(); 095 } 096 097 /** 098 * Get the current size of the buffer. 099 */ 100 public int getLength() { 101 return size; 102 } 103 104 /** 105 * Get the current size of the buffer. 106 * @deprecated Use {@link #getLength()} instead. 107 */ 108 @Deprecated 109 public int getSize() { 110 return getLength(); 111 } 112 113 /** 114 * Change the size of the buffer. The values in the old range are preserved 115 * and any new values are undefined. The capacity is changed if it is 116 * necessary. 117 * @param size The new number of bytes 118 */ 119 public void setSize(int size) { 120 if (size > getCapacity()) { 121 setCapacity(size * 3 / 2); 122 } 123 this.size = size; 124 } 125 126 /** 127 * Get the capacity, which is the maximum size that could handled without 128 * resizing the backing storage. 129 * @return The number of bytes 130 */ 131 public int getCapacity() { 132 return bytes.length; 133 } 134 135 /** 136 * Change the capacity of the backing storage. 137 * The data is preserved. 138 * @param new_cap The new capacity in bytes. 139 */ 140 public void setCapacity(int new_cap) { 141 if (new_cap != getCapacity()) { 142 byte[] new_data = new byte[new_cap]; 143 if (new_cap < size) { 144 size = new_cap; 145 } 146 if (size != 0) { 147 System.arraycopy(bytes, 0, new_data, 0, size); 148 } 149 bytes = new_data; 150 } 151 } 152 153 /** 154 * Set the BytesWritable to the contents of the given newData. 155 * @param newData the value to set this BytesWritable to. 156 */ 157 public void set(BytesWritable newData) { 158 set(newData.bytes, 0, newData.size); 159 } 160 161 /** 162 * Set the value to a copy of the given byte range 163 * @param newData the new values to copy in 164 * @param offset the offset in newData to start at 165 * @param length the number of bytes to copy 166 */ 167 public void set(byte[] newData, int offset, int length) { 168 setSize(0); 169 setSize(length); 170 System.arraycopy(newData, offset, bytes, 0, size); 171 } 172 173 // inherit javadoc 174 public void readFields(DataInput in) throws IOException { 175 setSize(0); // clear the old data 176 setSize(in.readInt()); 177 in.readFully(bytes, 0, size); 178 } 179 180 // inherit javadoc 181 public void write(DataOutput out) throws IOException { 182 out.writeInt(size); 183 out.write(bytes, 0, size); 184 } 185 186 @Override 187 public int hashCode() { 188 return super.hashCode(); 189 } 190 191 /** 192 * Are the two byte sequences equal? 193 */ 194 @Override 195 public boolean equals(Object right_obj) { 196 if (right_obj instanceof BytesWritable) 197 return super.equals(right_obj); 198 return false; 199 } 200 201 /** 202 * Generate the stream of bytes as hex pairs separated by ' '. 203 */ 204 @Override 205 public String toString() { 206 StringBuilder sb = new StringBuilder(3*size); 207 for (int idx = 0; idx < size; idx++) { 208 // if not the first, put a blank separator in 209 if (idx != 0) { 210 sb.append(' '); 211 } 212 String num = Integer.toHexString(0xff & bytes[idx]); 213 // if it is only one digit, add a leading 0. 214 if (num.length() < 2) { 215 sb.append('0'); 216 } 217 sb.append(num); 218 } 219 return sb.toString(); 220 } 221 222 /** A Comparator optimized for BytesWritable. */ 223 public static class Comparator extends WritableComparator { 224 public Comparator() { 225 super(BytesWritable.class); 226 } 227 228 /** 229 * Compare the buffers in serialized form. 230 */ 231 @Override 232 public int compare(byte[] b1, int s1, int l1, 233 byte[] b2, int s2, int l2) { 234 return compareBytes(b1, s1+LENGTH_BYTES, l1-LENGTH_BYTES, 235 b2, s2+LENGTH_BYTES, l2-LENGTH_BYTES); 236 } 237 } 238 239 static { // register this comparator 240 WritableComparator.define(BytesWritable.class, new Comparator()); 241 } 242 243}