View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.giraph.utils;
20  
21  import java.io.IOException;
22  import java.lang.reflect.Field;
23  
24  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_BOOLEAN;
25  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_BYTE;
26  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_CHAR;
27  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_SHORT;
28  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_INT;
29  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_LONG;
30  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_FLOAT;
31  import static org.apache.giraph.utils.ByteUtils.SIZE_OF_DOUBLE;
32  
33  /**
34   * Byte array input stream that uses Unsafe methods to deserialize
35   * much faster
36   */
37  public class UnsafeArrayReads extends UnsafeReads {
38    /** Access to the unsafe class */
39    private static final sun.misc.Unsafe UNSAFE;
40    static {
41      try {
42        Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
43        field.setAccessible(true);
44        UNSAFE = (sun.misc.Unsafe) field.get(null);
45        // Checkstyle exception due to needing to check if unsafe is allowed
46        // CHECKSTYLE: stop IllegalCatch
47      } catch (Exception e) {
48        // CHECKSTYLE: resume IllegalCatch
49        throw new RuntimeException("UnsafeArrayReads: Failed to " +
50            "get unsafe", e);
51      }
52    }
53    /** Offset of a byte array */
54    private static final long BYTE_ARRAY_OFFSET  =
55        UNSAFE.arrayBaseOffset(byte[].class);
56  
57    /** Byte buffer */
58    protected byte[] buf;
59  
60    /**
61     * Constructor
62     *
63     * @param buf Buffer to read from
64     */
65    public UnsafeArrayReads(byte[] buf) {
66      super(buf.length);
67      this.buf = buf;
68    }
69  
70    /**
71     * Constructor.
72     *
73     * @param buf Buffer to read from
74     * @param offset Offsetin the buffer to start reading from
75     * @param length Max length of the buffer to read
76     */
77    public UnsafeArrayReads(byte[] buf, int offset, int length) {
78      super(offset, length);
79      this.buf = buf;
80    }
81  
82    @Override
83    public int available() {
84      return (int) (bufLength - pos);
85    }
86  
87    @Override
88    public boolean endOfInput() {
89      return available() == 0;
90    }
91  
92  
93    @Override
94    public int getPos() {
95      return (int) pos;
96    }
97  
98    @Override
99    public void readFully(byte[] b) throws IOException {
100     ensureRemaining(b.length);
101     System.arraycopy(buf, (int) pos, b, 0, b.length);
102     pos += b.length;
103   }
104 
105   @Override
106   public void readFully(byte[] b, int off, int len) throws IOException {
107     ensureRemaining(len);
108     System.arraycopy(buf, (int) pos, b, off, len);
109     pos += len;
110   }
111 
112   @Override
113   public boolean readBoolean() throws IOException {
114     ensureRemaining(SIZE_OF_BOOLEAN);
115     boolean value = UNSAFE.getBoolean(buf,
116         BYTE_ARRAY_OFFSET + pos);
117     pos += SIZE_OF_BOOLEAN;
118     return value;
119   }
120 
121   @Override
122   public byte readByte() throws IOException {
123     ensureRemaining(SIZE_OF_BYTE);
124     byte value = UNSAFE.getByte(buf,
125         BYTE_ARRAY_OFFSET + pos);
126     pos += SIZE_OF_BYTE;
127     return value;
128   }
129 
130   @Override
131   public int readUnsignedByte() throws IOException {
132     return (short) (readByte() & 0xFF);
133   }
134 
135   @Override
136   public short readShort() throws IOException {
137     ensureRemaining(SIZE_OF_SHORT);
138     short value = UNSAFE.getShort(buf,
139         BYTE_ARRAY_OFFSET + pos);
140     pos += SIZE_OF_SHORT;
141     return value;
142   }
143 
144   @Override
145   public int readUnsignedShort() throws IOException {
146     return readShort() & 0xFFFF;
147   }
148 
149   @Override
150   public char readChar() throws IOException {
151     ensureRemaining(SIZE_OF_CHAR);
152     char value = UNSAFE.getChar(buf,
153         BYTE_ARRAY_OFFSET + pos);
154     pos += SIZE_OF_CHAR;
155     return value;
156   }
157 
158   @Override
159   public int readInt() throws IOException {
160     ensureRemaining(SIZE_OF_INT);
161     int value = UNSAFE.getInt(buf,
162         BYTE_ARRAY_OFFSET + pos);
163     pos += SIZE_OF_INT;
164     return value;
165   }
166 
167   @Override
168   public long readLong() throws IOException {
169     ensureRemaining(SIZE_OF_LONG);
170     long value = UNSAFE.getLong(buf,
171         BYTE_ARRAY_OFFSET + pos);
172     pos += SIZE_OF_LONG;
173     return value;
174   }
175 
176   @Override
177   public float readFloat() throws IOException {
178     ensureRemaining(SIZE_OF_FLOAT);
179     float value = UNSAFE.getFloat(buf,
180         BYTE_ARRAY_OFFSET + pos);
181     pos += SIZE_OF_FLOAT;
182     return value;
183   }
184 
185   @Override
186   public double readDouble() throws IOException {
187     ensureRemaining(SIZE_OF_DOUBLE);
188     double value = UNSAFE.getDouble(buf,
189         BYTE_ARRAY_OFFSET + pos);
190     pos += SIZE_OF_DOUBLE;
191     return value;
192   }
193 
194   /**
195    * Get an int at an arbitrary position in a byte[]
196    *
197    * @param buf Buffer to get the int from
198    * @param pos Position in the buffer to get the int from
199    * @return Int at the buffer position
200    */
201   public static int getInt(byte[] buf, int pos) {
202     return UNSAFE.getInt(buf,
203         BYTE_ARRAY_OFFSET + pos);
204   }
205 }