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 sequence 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 @Override 085 public byte[] getBytes() { 086 return bytes; 087 } 088 089 /** 090 * Get the data from the BytesWritable. 091 * @deprecated Use {@link #getBytes()} instead. 092 */ 093 @Deprecated 094 public byte[] get() { 095 return getBytes(); 096 } 097 098 /** 099 * Get the current size of the buffer. 100 */ 101 @Override 102 public int getLength() { 103 return size; 104 } 105 106 /** 107 * Get the current size of the buffer. 108 * @deprecated Use {@link #getLength()} instead. 109 */ 110 @Deprecated 111 public int getSize() { 112 return getLength(); 113 } 114 115 /** 116 * Change the size of the buffer. The values in the old range are preserved 117 * and any new values are undefined. The capacity is changed if it is 118 * necessary. 119 * @param size The new number of bytes 120 */ 121 public void setSize(int size) { 122 if (size > getCapacity()) { 123 // Avoid overflowing the int too early by casting to a long. 124 long newSize = Math.min(Integer.MAX_VALUE, (3L * size) / 2L); 125 setCapacity((int) newSize); 126 } 127 this.size = size; 128 } 129 130 /** 131 * Get the capacity, which is the maximum size that could handled without 132 * resizing the backing storage. 133 * @return The number of bytes 134 */ 135 public int getCapacity() { 136 return bytes.length; 137 } 138 139 /** 140 * Change the capacity of the backing storage. 141 * The data is preserved. 142 * @param new_cap The new capacity in bytes. 143 */ 144 public void setCapacity(int new_cap) { 145 if (new_cap != getCapacity()) { 146 byte[] new_data = new byte[new_cap]; 147 if (new_cap < size) { 148 size = new_cap; 149 } 150 if (size != 0) { 151 System.arraycopy(bytes, 0, new_data, 0, size); 152 } 153 bytes = new_data; 154 } 155 } 156 157 /** 158 * Set the BytesWritable to the contents of the given newData. 159 * @param newData the value to set this BytesWritable to. 160 */ 161 public void set(BytesWritable newData) { 162 set(newData.bytes, 0, newData.size); 163 } 164 165 /** 166 * Set the value to a copy of the given byte range 167 * @param newData the new values to copy in 168 * @param offset the offset in newData to start at 169 * @param length the number of bytes to copy 170 */ 171 public void set(byte[] newData, int offset, int length) { 172 setSize(0); 173 setSize(length); 174 System.arraycopy(newData, offset, bytes, 0, size); 175 } 176 177 // inherit javadoc 178 @Override 179 public void readFields(DataInput in) throws IOException { 180 setSize(0); // clear the old data 181 setSize(in.readInt()); 182 in.readFully(bytes, 0, size); 183 } 184 185 // inherit javadoc 186 @Override 187 public void write(DataOutput out) throws IOException { 188 out.writeInt(size); 189 out.write(bytes, 0, size); 190 } 191 192 @Override 193 public int hashCode() { 194 return super.hashCode(); 195 } 196 197 /** 198 * Are the two byte sequences equal? 199 */ 200 @Override 201 public boolean equals(Object right_obj) { 202 if (right_obj instanceof BytesWritable) 203 return super.equals(right_obj); 204 return false; 205 } 206 207 /** 208 * Generate the stream of bytes as hex pairs separated by ' '. 209 */ 210 @Override 211 public String toString() { 212 StringBuilder sb = new StringBuilder(3*size); 213 for (int idx = 0; idx < size; idx++) { 214 // if not the first, put a blank separator in 215 if (idx != 0) { 216 sb.append(' '); 217 } 218 String num = Integer.toHexString(0xff & bytes[idx]); 219 // if it is only one digit, add a leading 0. 220 if (num.length() < 2) { 221 sb.append('0'); 222 } 223 sb.append(num); 224 } 225 return sb.toString(); 226 } 227 228 /** A Comparator optimized for BytesWritable. */ 229 public static class Comparator extends WritableComparator { 230 public Comparator() { 231 super(BytesWritable.class); 232 } 233 234 /** 235 * Compare the buffers in serialized form. 236 */ 237 @Override 238 public int compare(byte[] b1, int s1, int l1, 239 byte[] b2, int s2, int l2) { 240 return compareBytes(b1, s1+LENGTH_BYTES, l1-LENGTH_BYTES, 241 b2, s2+LENGTH_BYTES, l2-LENGTH_BYTES); 242 } 243 } 244 245 static { // register this comparator 246 WritableComparator.define(BytesWritable.class, new Comparator()); 247 } 248 249}