View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to you under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14   * License for the specific language governing permissions and limitations
15   * under the License.
16   */
17  package org.apache.hadoop.hbase.util;
18  
19  import static org.junit.Assert.assertArrayEquals;
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.DataInputStream;
28  import java.io.DataOutputStream;
29  import java.io.IOException;
30  import java.nio.ByteBuffer;
31  import java.util.Collection;
32  import java.util.Collections;
33  import java.util.Set;
34  import java.util.SortedSet;
35  import java.util.TreeSet;
36  
37  import org.apache.hadoop.hbase.testclassification.SmallTests;
38  import org.apache.hadoop.io.WritableUtils;
39  import org.junit.Before;
40  import org.junit.Test;
41  import org.junit.experimental.categories.Category;
42  
43  @Category(SmallTests.class)
44  public class TestByteBufferUtils {
45  
46    private byte[] array;
47  
48    /**
49     * Create an array with sample data.
50     */
51    @Before
52    public void setUp() {
53      array = new byte[8];
54      for (int i = 0; i < array.length; ++i) {
55        array[i] = (byte) ('a' + i);
56      }
57    }
58  
59    private static final int MAX_VLONG_LENGTH = 9;
60    private static final Collection<Long> testNumbers;
61  
62    private static void addNumber(Set<Long> a, long l) {
63      if (l != Long.MIN_VALUE) {
64        a.add(l - 1);
65      }
66      a.add(l);
67      if (l != Long.MAX_VALUE) {
68        a.add(l + 1);
69      }
70      for (long divisor = 3; divisor <= 10; ++divisor) {
71        for (long delta = -1; delta <= 1; ++delta) {
72          a.add(l / divisor + delta);
73        }
74      }
75    }
76  
77    static {
78      SortedSet<Long> a = new TreeSet<Long>();
79      for (int i = 0; i <= 63; ++i) {
80        long v = (-1L) << i;
81        assertTrue(v < 0);
82        addNumber(a, v);
83        v = (1L << i) - 1;
84        assertTrue(v >= 0);
85        addNumber(a, v);
86      }
87  
88      testNumbers = Collections.unmodifiableSet(a);
89      System.err.println("Testing variable-length long serialization using: "
90          + testNumbers + " (count: " + testNumbers.size() + ")");
91      assertEquals(1753, testNumbers.size());
92      assertEquals(Long.MIN_VALUE, a.first().longValue());
93      assertEquals(Long.MAX_VALUE, a.last().longValue());
94    }
95  
96    @Test
97    public void testReadWriteVLong() {
98      for (long l : testNumbers) {
99        ByteBuffer b = ByteBuffer.allocate(MAX_VLONG_LENGTH);
100       ByteBufferUtils.writeVLong(b, l);
101       b.flip();
102       assertEquals(l, ByteBufferUtils.readVLong(b));
103     }
104   }
105 
106   @Test
107   public void testConsistencyWithHadoopVLong() throws IOException {
108     ByteArrayOutputStream baos = new ByteArrayOutputStream();
109     DataOutputStream dos = new DataOutputStream(baos);
110     for (long l : testNumbers) {
111       baos.reset();
112       ByteBuffer b = ByteBuffer.allocate(MAX_VLONG_LENGTH);
113       ByteBufferUtils.writeVLong(b, l);
114       String bufStr = Bytes.toStringBinary(b.array(),
115           b.arrayOffset(), b.position());
116       WritableUtils.writeVLong(dos, l);
117       String baosStr = Bytes.toStringBinary(baos.toByteArray());
118       assertEquals(baosStr, bufStr);
119     }
120   }
121 
122   /**
123    * Test copying to stream from buffer.
124    */
125   @Test
126   public void testMoveBufferToStream() {
127     final int arrayOffset = 7;
128     final int initialPosition = 10;
129     final int endPadding = 5;
130     byte[] arrayWrapper =
131         new byte[arrayOffset + initialPosition + array.length + endPadding];
132     System.arraycopy(array, 0, arrayWrapper,
133         arrayOffset + initialPosition, array.length);
134     ByteBuffer buffer = ByteBuffer.wrap(arrayWrapper, arrayOffset,
135         initialPosition + array.length).slice();
136     assertEquals(initialPosition + array.length, buffer.limit());
137     assertEquals(0, buffer.position());
138     buffer.position(initialPosition);
139     ByteArrayOutputStream bos = new ByteArrayOutputStream();
140     try {
141       ByteBufferUtils.moveBufferToStream(bos, buffer, array.length);
142     } catch (IOException e) {
143       fail("IOException in testCopyToStream()");
144     }
145     assertArrayEquals(array, bos.toByteArray());
146     assertEquals(initialPosition + array.length, buffer.position());
147   }
148 
149   /**
150    * Test copying to stream from buffer with offset.
151    * @throws IOException On test failure.
152    */
153   @Test
154   public void testCopyToStreamWithOffset() throws IOException {
155     ByteBuffer buffer = ByteBuffer.wrap(array);
156 
157     ByteArrayOutputStream bos = new ByteArrayOutputStream();
158 
159     ByteBufferUtils.copyBufferToStream(bos, buffer, array.length / 2,
160         array.length / 2);
161 
162     byte[] returnedArray = bos.toByteArray();
163     for (int i = 0; i < array.length / 2; ++i) {
164       int pos = array.length / 2 + i;
165       assertEquals(returnedArray[i], array[pos]);
166     }
167   }
168 
169   /**
170    * Test copying data from stream.
171    * @throws IOException On test failure.
172    */
173   @Test
174   public void testCopyFromStream() throws IOException {
175     ByteBuffer buffer = ByteBuffer.allocate(array.length);
176     ByteArrayInputStream bis = new ByteArrayInputStream(array);
177     DataInputStream dis = new DataInputStream(bis);
178 
179     ByteBufferUtils.copyFromStreamToBuffer(buffer, dis, array.length / 2);
180     ByteBufferUtils.copyFromStreamToBuffer(buffer, dis,
181         array.length - array.length / 2);
182     for (int i = 0; i < array.length; ++i) {
183       assertEquals(array[i], buffer.get(i));
184     }
185   }
186 
187   /**
188    * Test copying from buffer.
189    */
190   @Test
191   public void testCopyFromBuffer() {
192     ByteBuffer srcBuffer = ByteBuffer.allocate(array.length);
193     ByteBuffer dstBuffer = ByteBuffer.allocate(array.length);
194     srcBuffer.put(array);
195 
196     ByteBufferUtils.copyFromBufferToBuffer(dstBuffer, srcBuffer,
197         array.length / 2, array.length / 4);
198     for (int i = 0; i < array.length / 4; ++i) {
199       assertEquals(srcBuffer.get(i + array.length / 2),
200           dstBuffer.get(i));
201     }
202   }
203 
204   /**
205    * Test 7-bit encoding of integers.
206    * @throws IOException On test failure.
207    */
208   @Test
209   public void testCompressedInt() throws IOException {
210     testCompressedInt(0);
211     testCompressedInt(Integer.MAX_VALUE);
212     testCompressedInt(Integer.MIN_VALUE);
213 
214     for (int i = 0; i < 3; i++) {
215       testCompressedInt((128 << i) - 1);
216     }
217 
218     for (int i = 0; i < 3; i++) {
219       testCompressedInt((128 << i));
220     }
221   }
222 
223   /**
224    * Test how much bytes we need to store integer.
225    */
226   @Test
227   public void testIntFitsIn() {
228     assertEquals(1, ByteBufferUtils.intFitsIn(0));
229     assertEquals(1, ByteBufferUtils.intFitsIn(1));
230     assertEquals(2, ByteBufferUtils.intFitsIn(1 << 8));
231     assertEquals(3, ByteBufferUtils.intFitsIn(1 << 16));
232     assertEquals(4, ByteBufferUtils.intFitsIn(-1));
233     assertEquals(4, ByteBufferUtils.intFitsIn(Integer.MAX_VALUE));
234     assertEquals(4, ByteBufferUtils.intFitsIn(Integer.MIN_VALUE));
235   }
236 
237   /**
238    * Test how much bytes we need to store long.
239    */
240   @Test
241   public void testLongFitsIn() {
242     assertEquals(1, ByteBufferUtils.longFitsIn(0));
243     assertEquals(1, ByteBufferUtils.longFitsIn(1));
244     assertEquals(3, ByteBufferUtils.longFitsIn(1l << 16));
245     assertEquals(5, ByteBufferUtils.longFitsIn(1l << 32));
246     assertEquals(8, ByteBufferUtils.longFitsIn(-1));
247     assertEquals(8, ByteBufferUtils.longFitsIn(Long.MIN_VALUE));
248     assertEquals(8, ByteBufferUtils.longFitsIn(Long.MAX_VALUE));
249   }
250 
251   /**
252    * Test if we are comparing equal bytes.
253    */
254   @Test
255   public void testArePartEqual() {
256     byte[] array = new byte[] { 1, 2, 3, 4, 5, 1, 2, 3, 4 };
257     ByteBuffer buffer = ByteBuffer.wrap(array);
258     assertTrue(ByteBufferUtils.arePartsEqual(buffer, 0, 4, 5, 4));
259     assertTrue(ByteBufferUtils.arePartsEqual(buffer, 1, 2, 6, 2));
260     assertFalse(ByteBufferUtils.arePartsEqual(buffer, 1, 2, 6, 3));
261     assertFalse(ByteBufferUtils.arePartsEqual(buffer, 1, 3, 6, 2));
262     assertFalse(ByteBufferUtils.arePartsEqual(buffer, 0, 3, 6, 3));
263   }
264 
265   /**
266    * Test serializing int to bytes
267    */
268   @Test
269   public void testPutInt() {
270     testPutInt(0);
271     testPutInt(Integer.MAX_VALUE);
272 
273     for (int i = 0; i < 3; i++) {
274       testPutInt((128 << i) - 1);
275     }
276 
277     for (int i = 0; i < 3; i++) {
278       testPutInt((128 << i));
279     }
280   }
281 
282   // Utility methods invoked from test methods
283 
284   private void testCompressedInt(int value) throws IOException {
285     int parsedValue = 0;
286 
287     ByteArrayOutputStream bos = new ByteArrayOutputStream();
288     ByteBufferUtils.putCompressedInt(bos, value);
289 
290     ByteArrayInputStream bis = new ByteArrayInputStream(
291         bos.toByteArray());
292     parsedValue = ByteBufferUtils.readCompressedInt(bis);
293 
294     assertEquals(value, parsedValue);
295   }
296 
297   private void testPutInt(int value) {
298     ByteArrayOutputStream baos = new ByteArrayOutputStream();
299     try {
300       ByteBufferUtils.putInt(baos, value);
301     } catch (IOException e) {
302       throw new RuntimeException("Bug in putIn()", e);
303     }
304 
305     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
306     DataInputStream dis = new DataInputStream(bais);
307     try {
308       assertEquals(dis.readInt(), value);
309     } catch (IOException e) {
310       throw new RuntimeException("Bug in test!", e);
311     }
312   }
313 
314   @Test
315   public void testToBytes(){
316     ByteBuffer buffer = ByteBuffer.allocate(5);
317     buffer.put(new byte[]{0,1,2,3,4});
318     assertEquals(5, buffer.position());
319     assertEquals(5, buffer.limit());
320     byte[] copy = ByteBufferUtils.toBytes(buffer, 2);
321     assertArrayEquals(new byte[]{2,3,4}, copy);
322     assertEquals(5, buffer.position());
323     assertEquals(5, buffer.limit());
324   }
325 }