/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.internal.direct.stream.v2; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.RandomAccess; import java.util.UUID; import org.apache.ignite.internal.direct.stream.DirectByteBufferStream; import org.apache.ignite.internal.util.GridUnsafe; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageWriter; import sun.nio.ch.DirectBuffer; import static org.apache.ignite.internal.util.GridUnsafe.BIG_ENDIAN; import static org.apache.ignite.internal.util.GridUnsafe.BYTE_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.CHAR_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.DOUBLE_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.FLOAT_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.INT_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.LONG_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.SHORT_ARR_OFF; /** * Direct marshalling I/O stream (version 2). */ public class DirectByteBufferStreamImplV2 implements DirectByteBufferStream { /** */ private static final byte[] BYTE_ARR_EMPTY = new byte[0]; /** */ private static final short[] SHORT_ARR_EMPTY = new short[0]; /** */ private static final int[] INT_ARR_EMPTY = U.EMPTY_INTS; /** */ private static final long[] LONG_ARR_EMPTY = U.EMPTY_LONGS; /** */ private static final float[] FLOAT_ARR_EMPTY = new float[0]; /** */ private static final double[] DOUBLE_ARR_EMPTY = new double[0]; /** */ private static final char[] CHAR_ARR_EMPTY = new char[0]; /** */ private static final boolean[] BOOLEAN_ARR_EMPTY = new boolean[0]; /** */ private static final ArrayCreator<byte[]> BYTE_ARR_CREATOR = new ArrayCreator<byte[]>() { @Override public byte[] create(int len) { assert len >= 0; switch (len) { case 0: return BYTE_ARR_EMPTY; default: return new byte[len]; } } }; /** */ private static final ArrayCreator<short[]> SHORT_ARR_CREATOR = new ArrayCreator<short[]>() { @Override public short[] create(int len) { assert len >= 0; switch (len) { case 0: return SHORT_ARR_EMPTY; default: return new short[len]; } } }; /** */ private static final ArrayCreator<int[]> INT_ARR_CREATOR = new ArrayCreator<int[]>() { @Override public int[] create(int len) { assert len >= 0; switch (len) { case 0: return INT_ARR_EMPTY; default: return new int[len]; } } }; /** */ private static final ArrayCreator<long[]> LONG_ARR_CREATOR = new ArrayCreator<long[]>() { @Override public long[] create(int len) { assert len >= 0; switch (len) { case 0: return LONG_ARR_EMPTY; default: return new long[len]; } } }; /** */ private static final ArrayCreator<float[]> FLOAT_ARR_CREATOR = new ArrayCreator<float[]>() { @Override public float[] create(int len) { assert len >= 0; switch (len) { case 0: return FLOAT_ARR_EMPTY; default: return new float[len]; } } }; /** */ private static final ArrayCreator<double[]> DOUBLE_ARR_CREATOR = new ArrayCreator<double[]>() { @Override public double[] create(int len) { assert len >= 0; switch (len) { case 0: return DOUBLE_ARR_EMPTY; default: return new double[len]; } } }; /** */ private static final ArrayCreator<char[]> CHAR_ARR_CREATOR = new ArrayCreator<char[]>() { @Override public char[] create(int len) { assert len >= 0; switch (len) { case 0: return CHAR_ARR_EMPTY; default: return new char[len]; } } }; /** */ private static final ArrayCreator<boolean[]> BOOLEAN_ARR_CREATOR = new ArrayCreator<boolean[]>() { @Override public boolean[] create(int len) { assert len >= 0; switch (len) { case 0: return BOOLEAN_ARR_EMPTY; default: return new boolean[len]; } } }; /** */ private static final Object NULL = new Object(); /** */ @GridToStringExclude private final MessageFactory msgFactory; /** */ private ByteBuffer buf; /** */ private byte[] heapArr; /** */ private long baseOff; /** */ private int arrOff = -1; /** */ private Object tmpArr; /** */ private int tmpArrOff; /** */ private int tmpArrBytes; /** */ private boolean msgTypeDone; /** */ private Message msg; /** */ private Iterator<?> mapIt; /** */ private Iterator<?> it; /** */ private int arrPos = -1; /** */ private Object arrCur = NULL; /** */ private Object mapCur = NULL; /** */ private Object cur = NULL; /** */ private boolean keyDone; /** */ private int readSize = -1; /** */ private int readItems; /** */ private Object[] objArr; /** */ private Collection<Object> col; /** */ private Map<Object, Object> map; /** */ private long prim; /** */ private int primShift; /** */ private int uuidState; /** */ private long uuidMost; /** */ private long uuidLeast; /** */ private long uuidLocId; /** */ private boolean lastFinished; /** * @param msgFactory Message factory. */ public DirectByteBufferStreamImplV2(MessageFactory msgFactory) { this.msgFactory = msgFactory; } /** {@inheritDoc} */ @Override public void setBuffer(ByteBuffer buf) { assert buf != null; if (this.buf != buf) { this.buf = buf; heapArr = buf.isDirect() ? null : buf.array(); baseOff = buf.isDirect() ? ((DirectBuffer)buf).address() : BYTE_ARR_OFF; } } /** {@inheritDoc} */ @Override public int remaining() { return buf.remaining(); } /** {@inheritDoc} */ @Override public boolean lastFinished() { return lastFinished; } /** {@inheritDoc} */ @Override public void writeByte(byte val) { lastFinished = buf.remaining() >= 1; if (lastFinished) { int pos = buf.position(); GridUnsafe.putByte(heapArr, baseOff + pos, val); buf.position(pos + 1); } } /** {@inheritDoc} */ @Override public void writeShort(short val) { lastFinished = buf.remaining() >= 2; if (lastFinished) { int pos = buf.position(); long off = baseOff + pos; if (BIG_ENDIAN) GridUnsafe.putShortLE(heapArr, off, val); else GridUnsafe.putShort(heapArr, off, val); buf.position(pos + 2); } } /** {@inheritDoc} */ @Override public void writeInt(int val) { lastFinished = buf.remaining() >= 5; if (lastFinished) { if (val == Integer.MAX_VALUE) val = Integer.MIN_VALUE; else val++; int pos = buf.position(); while ((val & 0xFFFF_FF80) != 0) { byte b = (byte)(val | 0x80); GridUnsafe.putByte(heapArr, baseOff + pos++, b); val >>>= 7; } GridUnsafe.putByte(heapArr, baseOff + pos++, (byte)val); buf.position(pos); } } /** {@inheritDoc} */ @Override public void writeLong(long val) { lastFinished = buf.remaining() >= 10; if (lastFinished) { if (val == Long.MAX_VALUE) val = Long.MIN_VALUE; else val++; int pos = buf.position(); while ((val & 0xFFFF_FFFF_FFFF_FF80L) != 0) { byte b = (byte)(val | 0x80); GridUnsafe.putByte(heapArr, baseOff + pos++, b); val >>>= 7; } GridUnsafe.putByte(heapArr, baseOff + pos++, (byte)val); buf.position(pos); } } /** {@inheritDoc} */ @Override public void writeFloat(float val) { lastFinished = buf.remaining() >= 4; if (lastFinished) { int pos = buf.position(); long off = baseOff + pos; if (BIG_ENDIAN) GridUnsafe.putFloatLE(heapArr, off, val); else GridUnsafe.putFloat(heapArr, off, val); buf.position(pos + 4); } } /** {@inheritDoc} */ @Override public void writeDouble(double val) { lastFinished = buf.remaining() >= 8; if (lastFinished) { int pos = buf.position(); long off = baseOff + pos; if (BIG_ENDIAN) GridUnsafe.putDoubleLE(heapArr, off, val); else GridUnsafe.putDouble(heapArr, off, val); buf.position(pos + 8); } } /** {@inheritDoc} */ @Override public void writeChar(char val) { lastFinished = buf.remaining() >= 2; if (lastFinished) { int pos = buf.position(); long off = baseOff + pos; if (BIG_ENDIAN) GridUnsafe.putCharLE(heapArr, off, val); else GridUnsafe.putChar(heapArr, off, val); buf.position(pos + 2); } } /** {@inheritDoc} */ @Override public void writeBoolean(boolean val) { lastFinished = buf.remaining() >= 1; if (lastFinished) { int pos = buf.position(); GridUnsafe.putBoolean(heapArr, baseOff + pos, val); buf.position(pos + 1); } } /** {@inheritDoc} */ @Override public void writeByteArray(byte[] val) { if (val != null) lastFinished = writeArray(val, BYTE_ARR_OFF, val.length, val.length); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeByteArray(byte[] val, long off, int len) { if (val != null) lastFinished = writeArray(val, BYTE_ARR_OFF + off, len, len); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeShortArray(short[] val) { if (val != null) if (BIG_ENDIAN) lastFinished = writeArrayLE(val, SHORT_ARR_OFF, val.length, 2, 1); else lastFinished = writeArray(val, SHORT_ARR_OFF, val.length, val.length << 1); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeIntArray(int[] val) { if (val != null) if (BIG_ENDIAN) lastFinished = writeArrayLE(val, INT_ARR_OFF, val.length, 4, 2); else lastFinished = writeArray(val, INT_ARR_OFF, val.length, val.length << 2); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeLongArray(long[] val) { if (val != null) if (BIG_ENDIAN) lastFinished = writeArrayLE(val, LONG_ARR_OFF, val.length, 8, 3); else lastFinished = writeArray(val, LONG_ARR_OFF, val.length, val.length << 3); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeFloatArray(float[] val) { if (val != null) if (BIG_ENDIAN) lastFinished = writeArrayLE(val, FLOAT_ARR_OFF, val.length, 4, 2); else lastFinished = writeArray(val, FLOAT_ARR_OFF, val.length, val.length << 2); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeDoubleArray(double[] val) { if (val != null) if (BIG_ENDIAN) lastFinished = writeArrayLE(val, DOUBLE_ARR_OFF, val.length, 8, 3); else lastFinished = writeArray(val, DOUBLE_ARR_OFF, val.length, val.length << 3); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeCharArray(char[] val) { if (val != null) { if (BIG_ENDIAN) lastFinished = writeArrayLE(val, CHAR_ARR_OFF, val.length, 2, 1); else lastFinished = writeArray(val, CHAR_ARR_OFF, val.length, val.length << 1); } else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeBooleanArray(boolean[] val) { if (val != null) lastFinished = writeArray(val, GridUnsafe.BOOLEAN_ARR_OFF, val.length, val.length); else writeInt(-1); } /** {@inheritDoc} */ @Override public void writeString(String val) { writeByteArray(val != null ? val.getBytes() : null); } /** {@inheritDoc} */ @Override public void writeBitSet(BitSet val) { writeLongArray(val != null ? val.toLongArray() : null); } /** {@inheritDoc} */ @Override public void writeUuid(UUID val) { switch (uuidState) { case 0: writeBoolean(val == null); if (!lastFinished || val == null) return; uuidState++; case 1: writeLong(val.getMostSignificantBits()); if (!lastFinished) return; uuidState++; case 2: writeLong(val.getLeastSignificantBits()); if (!lastFinished) return; uuidState = 0; } } /** {@inheritDoc} */ @Override public void writeIgniteUuid(IgniteUuid val) { switch (uuidState) { case 0: writeBoolean(val == null); if (!lastFinished || val == null) return; uuidState++; case 1: writeLong(val.globalId().getMostSignificantBits()); if (!lastFinished) return; uuidState++; case 2: writeLong(val.globalId().getLeastSignificantBits()); if (!lastFinished) return; uuidState++; case 3: writeLong(val.localId()); if (!lastFinished) return; uuidState = 0; } } /** {@inheritDoc} */ @Override public void writeMessage(Message msg, MessageWriter writer) { if (msg != null) { if (buf.hasRemaining()) { try { writer.beforeInnerMessageWrite(); writer.setCurrentWriteClass(msg.getClass()); lastFinished = msg.writeTo(buf, writer); } finally { writer.afterInnerMessageWrite(lastFinished); } } else lastFinished = false; } else writeShort(Short.MIN_VALUE); } /** {@inheritDoc} */ @Override public <T> void writeObjectArray(T[] arr, MessageCollectionItemType itemType, MessageWriter writer) { if (arr != null) { int len = arr.length; if (arrPos == -1) { writeInt(len); if (!lastFinished) return; arrPos = 0; } while (arrPos < len || arrCur != NULL) { if (arrCur == NULL) arrCur = arr[arrPos++]; write(itemType, arrCur, writer); if (!lastFinished) return; arrCur = NULL; } arrPos = -1; } else writeInt(-1); } /** {@inheritDoc} */ @Override public <T> void writeCollection(Collection<T> col, MessageCollectionItemType itemType, MessageWriter writer) { if (col != null) { if (col instanceof List && col instanceof RandomAccess) writeRandomAccessList((List<T>)col, itemType, writer); else { if (it == null) { writeInt(col.size()); if (!lastFinished) return; it = col.iterator(); } while (it.hasNext() || cur != NULL) { if (cur == NULL) cur = it.next(); write(itemType, cur, writer); if (!lastFinished) return; cur = NULL; } it = null; } } else writeInt(-1); } /** * @param list List. * @param itemType Component type. * @param writer Writer. */ private <T> void writeRandomAccessList(List<T> list, MessageCollectionItemType itemType, MessageWriter writer) { assert list instanceof RandomAccess; int size = list.size(); if (arrPos == -1) { writeInt(size); if (!lastFinished) return; arrPos = 0; } while (arrPos < size || arrCur != NULL) { if (arrCur == NULL) arrCur = list.get(arrPos++); write(itemType, arrCur, writer); if (!lastFinished) return; arrCur = NULL; } arrPos = -1; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <K, V> void writeMap(Map<K, V> map, MessageCollectionItemType keyType, MessageCollectionItemType valType, MessageWriter writer) { if (map != null) { if (mapIt == null) { writeInt(map.size()); if (!lastFinished) return; mapIt = map.entrySet().iterator(); } while (mapIt.hasNext() || mapCur != NULL) { Map.Entry<K, V> e; if (mapCur == NULL) mapCur = mapIt.next(); e = (Map.Entry<K, V>)mapCur; if (!keyDone) { write(keyType, e.getKey(), writer); if (!lastFinished) return; keyDone = true; } write(valType, e.getValue(), writer); if (!lastFinished) return; mapCur = NULL; keyDone = false; } mapIt = null; } else writeInt(-1); } /** {@inheritDoc} */ @Override public byte readByte() { lastFinished = buf.remaining() >= 1; if (lastFinished) { int pos = buf.position(); buf.position(pos + 1); return GridUnsafe.getByte(heapArr, baseOff + pos); } else return 0; } /** {@inheritDoc} */ @Override public short readShort() { lastFinished = buf.remaining() >= 2; if (lastFinished) { int pos = buf.position(); buf.position(pos + 2); long off = baseOff + pos; return BIG_ENDIAN ? GridUnsafe.getShortLE(heapArr, off) : GridUnsafe.getShort(heapArr, off); } else return 0; } /** {@inheritDoc} */ @Override public int readInt() { lastFinished = false; int val = 0; while (buf.hasRemaining()) { int pos = buf.position(); byte b = GridUnsafe.getByte(heapArr, baseOff + pos); buf.position(pos + 1); prim |= ((long)b & 0x7F) << (7 * primShift); if ((b & 0x80) == 0) { lastFinished = true; val = (int)prim; if (val == Integer.MIN_VALUE) val = Integer.MAX_VALUE; else val--; prim = 0; primShift = 0; break; } else primShift++; } return val; } /** {@inheritDoc} */ @Override public long readLong() { lastFinished = false; long val = 0; while (buf.hasRemaining()) { int pos = buf.position(); byte b = GridUnsafe.getByte(heapArr, baseOff + pos); buf.position(pos + 1); prim |= ((long)b & 0x7F) << (7 * primShift); if ((b & 0x80) == 0) { lastFinished = true; val = prim; if (val == Long.MIN_VALUE) val = Long.MAX_VALUE; else val--; prim = 0; primShift = 0; break; } else primShift++; } return val; } /** {@inheritDoc} */ @Override public float readFloat() { lastFinished = buf.remaining() >= 4; if (lastFinished) { int pos = buf.position(); buf.position(pos + 4); long off = baseOff + pos; return BIG_ENDIAN ? GridUnsafe.getFloatLE(heapArr, off) : GridUnsafe.getFloat(heapArr, off); } else return 0; } /** {@inheritDoc} */ @Override public double readDouble() { lastFinished = buf.remaining() >= 8; if (lastFinished) { int pos = buf.position(); buf.position(pos + 8); long off = baseOff + pos; return BIG_ENDIAN ? GridUnsafe.getDoubleLE(heapArr, off) : GridUnsafe.getDouble(heapArr, off); } else return 0; } /** {@inheritDoc} */ @Override public char readChar() { lastFinished = buf.remaining() >= 2; if (lastFinished) { int pos = buf.position(); buf.position(pos + 2); long off = baseOff + pos; return BIG_ENDIAN ? GridUnsafe.getCharLE(heapArr, off) : GridUnsafe.getChar(heapArr, off); } else return 0; } /** {@inheritDoc} */ @Override public boolean readBoolean() { lastFinished = buf.hasRemaining(); if (lastFinished) { int pos = buf.position(); buf.position(pos + 1); return GridUnsafe.getBoolean(heapArr, baseOff + pos); } else return false; } /** {@inheritDoc} */ @Override public byte[] readByteArray() { return readArray(BYTE_ARR_CREATOR, 0, BYTE_ARR_OFF); } /** {@inheritDoc} */ @Override public short[] readShortArray() { if (BIG_ENDIAN) return readArrayLE(SHORT_ARR_CREATOR, 2, 1, SHORT_ARR_OFF); else return readArray(SHORT_ARR_CREATOR, 1, SHORT_ARR_OFF); } /** {@inheritDoc} */ @Override public int[] readIntArray() { if (BIG_ENDIAN) return readArrayLE(INT_ARR_CREATOR, 4, 2, INT_ARR_OFF); else return readArray(INT_ARR_CREATOR, 2, INT_ARR_OFF); } /** {@inheritDoc} */ @Override public long[] readLongArray() { if (BIG_ENDIAN) return readArrayLE(LONG_ARR_CREATOR, 8, 3, LONG_ARR_OFF); else return readArray(LONG_ARR_CREATOR, 3, LONG_ARR_OFF); } /** {@inheritDoc} */ @Override public float[] readFloatArray() { if (BIG_ENDIAN) return readArrayLE(FLOAT_ARR_CREATOR, 4, 2, FLOAT_ARR_OFF); else return readArray(FLOAT_ARR_CREATOR, 2, FLOAT_ARR_OFF); } /** {@inheritDoc} */ @Override public double[] readDoubleArray() { if (BIG_ENDIAN) return readArrayLE(DOUBLE_ARR_CREATOR, 8, 3, DOUBLE_ARR_OFF); else return readArray(DOUBLE_ARR_CREATOR, 3, DOUBLE_ARR_OFF); } /** {@inheritDoc} */ @Override public char[] readCharArray() { if (BIG_ENDIAN) return readArrayLE(CHAR_ARR_CREATOR, 2, 1, CHAR_ARR_OFF); else return readArray(CHAR_ARR_CREATOR, 1, CHAR_ARR_OFF); } /** {@inheritDoc} */ @Override public boolean[] readBooleanArray() { return readArray(BOOLEAN_ARR_CREATOR, 0, GridUnsafe.BOOLEAN_ARR_OFF); } /** {@inheritDoc} */ @Override public String readString() { byte[] arr = readByteArray(); return arr != null ? new String(arr) : null; } /** {@inheritDoc} */ @Override public BitSet readBitSet() { long[] arr = readLongArray(); return arr != null ? BitSet.valueOf(arr) : null; } /** {@inheritDoc} */ @Override public UUID readUuid() { switch (uuidState) { case 0: boolean isNull = readBoolean(); if (!lastFinished || isNull) return null; uuidState++; case 1: uuidMost = readLong(); if (!lastFinished) return null; uuidState++; case 2: uuidLeast = readLong(); if (!lastFinished) return null; uuidState = 0; } UUID val = new UUID(uuidMost, uuidLeast); uuidMost = 0; uuidLeast = 0; return val; } /** {@inheritDoc} */ @Override public IgniteUuid readIgniteUuid() { switch (uuidState) { case 0: boolean isNull = readBoolean(); if (!lastFinished || isNull) return null; uuidState++; case 1: uuidMost = readLong(); if (!lastFinished) return null; uuidState++; case 2: uuidLeast = readLong(); if (!lastFinished) return null; uuidState++; case 3: uuidLocId = readLong(); if (!lastFinished) return null; uuidState = 0; } IgniteUuid val = new IgniteUuid(new UUID(uuidMost, uuidLeast), uuidLocId); uuidMost = 0; uuidLeast = 0; uuidLocId = 0; return val; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <T extends Message> T readMessage(MessageReader reader) { if (!msgTypeDone) { if (buf.remaining() < Message.DIRECT_TYPE_SIZE) { lastFinished = false; return null; } short type = readShort(); msg = type == Short.MIN_VALUE ? null : msgFactory.create(type); msgTypeDone = true; } if (msg != null) { try { reader.beforeInnerMessageRead(); reader.setCurrentReadClass(msg.getClass()); lastFinished = msg.readFrom(buf, reader); } finally { reader.afterInnerMessageRead(lastFinished); } } else lastFinished = true; if (lastFinished) { Message msg0 = msg; msgTypeDone = false; msg = null; return (T)msg0; } else return null; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <T> T[] readObjectArray(MessageCollectionItemType itemType, Class<T> itemCls, MessageReader reader) { if (readSize == -1) { int size = readInt(); if (!lastFinished) return null; readSize = size; } if (readSize >= 0) { if (objArr == null) objArr = itemCls != null ? (Object[])Array.newInstance(itemCls, readSize) : new Object[readSize]; for (int i = readItems; i < readSize; i++) { Object item = read(itemType, reader); if (!lastFinished) return null; objArr[i] = item; readItems++; } } readSize = -1; readItems = 0; cur = null; T[] objArr0 = (T[])objArr; objArr = null; return objArr0; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <C extends Collection<?>> C readCollection(MessageCollectionItemType itemType, MessageReader reader) { if (readSize == -1) { int size = readInt(); if (!lastFinished) return null; readSize = size; } if (readSize >= 0) { if (col == null) col = new ArrayList<>(readSize); for (int i = readItems; i < readSize; i++) { Object item = read(itemType, reader); if (!lastFinished) return null; col.add(item); readItems++; } } readSize = -1; readItems = 0; cur = null; C col0 = (C)col; col = null; return col0; } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public <M extends Map<?, ?>> M readMap(MessageCollectionItemType keyType, MessageCollectionItemType valType, boolean linked, MessageReader reader) { if (readSize == -1) { int size = readInt(); if (!lastFinished) return null; readSize = size; } if (readSize >= 0) { if (map == null) map = linked ? U.newLinkedHashMap(readSize) : U.newHashMap(readSize); for (int i = readItems; i < readSize; i++) { if (!keyDone) { Object key = read(keyType, reader); if (!lastFinished) return null; mapCur = key; keyDone = true; } Object val = read(valType, reader); if (!lastFinished) return null; map.put(mapCur, val); keyDone = false; readItems++; } } readSize = -1; readItems = 0; mapCur = null; M map0 = (M)map; map = null; return map0; } /** * @param arr Array. * @param off Offset. * @param len Length. * @param bytes Length in bytes. * @return Whether array was fully written. */ private boolean writeArray(Object arr, long off, int len, int bytes) { assert arr != null; assert arr.getClass().isArray() && arr.getClass().getComponentType().isPrimitive(); assert off > 0; assert len >= 0; assert bytes >= 0; assert bytes >= arrOff; if (writeArrayLength(len)) return false; int toWrite = bytes - arrOff; int pos = buf.position(); int remaining = buf.remaining(); if (toWrite <= remaining) { if (toWrite > 0) { GridUnsafe.copyMemory(arr, off + arrOff, heapArr, baseOff + pos, toWrite); buf.position(pos + toWrite); } arrOff = -1; return true; } else { if (remaining > 0) { GridUnsafe.copyMemory(arr, off + arrOff, heapArr, baseOff + pos, remaining); buf.position(pos + remaining); arrOff += remaining; } return false; } } /** * @param arr Array. * @param off Offset. * @param len Length. * @param typeSize Primitive type size in bytes. Needs for byte reverse. * @param shiftCnt Shift for length. * @return Whether array was fully written. */ private boolean writeArrayLE(Object arr, long off, int len, int typeSize, int shiftCnt) { assert arr != null; assert arr.getClass().isArray() && arr.getClass().getComponentType().isPrimitive(); assert off > 0; assert len >= 0; int bytes = len << shiftCnt; assert bytes >= arrOff; if (writeArrayLength(len)) return false; int toWrite = (bytes - arrOff) >> shiftCnt; int remaining = buf.remaining() >> shiftCnt; if (toWrite <= remaining) { writeArrayLE(arr, off, toWrite, typeSize); arrOff = -1; return true; } else { if (remaining > 0) writeArrayLE(arr, off, remaining, typeSize); return false; } } /** * @param arr Array. * @param off Offset. * @param len Length. * @param typeSize Primitive type size in bytes. */ private void writeArrayLE(Object arr, long off, int len, int typeSize) { int pos = buf.position(); for (int i = 0; i < len; i++) { for (int j = 0; j < typeSize; j++) { byte b = GridUnsafe.getByteField(arr, off + arrOff + (typeSize - j - 1)); GridUnsafe.putByte(heapArr, baseOff + pos++, b); } buf.position(pos); arrOff += typeSize; } } /** * @param len Length. */ private boolean writeArrayLength(int len) { if (arrOff == -1) { writeInt(len); if (!lastFinished) return true; arrOff = 0; } return false; } /** * @param creator Array creator. * @param lenShift Array length shift size. * @param off Base offset. * @return Array or special value if it was not fully read. */ @SuppressWarnings("unchecked") private <T> T readArray(ArrayCreator<T> creator, int lenShift, long off) { assert creator != null; if (tmpArr == null) { int len = readInt(); if (!lastFinished) return null; switch (len) { case -1: lastFinished = true; return null; case 0: lastFinished = true; return creator.create(0); default: tmpArr = creator.create(len); tmpArrBytes = len << lenShift; } } int toRead = tmpArrBytes - tmpArrOff; int remaining = buf.remaining(); int pos = buf.position(); lastFinished = toRead <= remaining; if (lastFinished) { GridUnsafe.copyMemory(heapArr, baseOff + pos, tmpArr, off + tmpArrOff, toRead); buf.position(pos + toRead); T arr = (T)tmpArr; tmpArr = null; tmpArrBytes = 0; tmpArrOff = 0; return arr; } else { GridUnsafe.copyMemory(heapArr, baseOff + pos, tmpArr, off + tmpArrOff, remaining); buf.position(pos + remaining); tmpArrOff += remaining; return null; } } /** * @param creator Array creator. * @param typeSize Primitive type size in bytes. * @param lenShift Array length shift size. * @param off Base offset. * @return Array or special value if it was not fully read. */ @SuppressWarnings("unchecked") private <T> T readArrayLE(ArrayCreator<T> creator, int typeSize, int lenShift, long off) { assert creator != null; if (tmpArr == null) { int len = readInt(); if (!lastFinished) return null; switch (len) { case -1: lastFinished = true; return null; case 0: lastFinished = true; return creator.create(0); default: tmpArr = creator.create(len); tmpArrBytes = len << lenShift; } } int toRead = (tmpArrBytes - tmpArrOff) >> lenShift; int remaining = buf.remaining() >> lenShift; lastFinished = toRead <= buf.remaining(); if (lastFinished) { readArrayLE(typeSize, off, toRead); T arr = (T)tmpArr; tmpArr = null; tmpArrBytes = 0; tmpArrOff = 0; return arr; } else { for (int i = 0; i < remaining; i++) { int pos = buf.position(); for (int j = 0; j < typeSize; j++) { byte b = GridUnsafe.getByte(heapArr, baseOff + pos + (typeSize - j - 1)); GridUnsafe.putByteField(tmpArr, off + tmpArrOff + j, b); } buf.position(pos + typeSize); tmpArrOff += typeSize; } tmpArrOff += buf.remaining(); return null; } } /** * @param typeSize Primitive type size in bytes. * @param off Offset. * @param toRead To read. */ private void readArrayLE(int typeSize, long off, int toRead) { for (int i = 0; i < toRead; i++) { int pos = buf.position(); for (int j = 0; j < typeSize; j++) { byte b = GridUnsafe.getByte(heapArr, baseOff + pos + (typeSize - j - 1)); GridUnsafe.putByteField(tmpArr, off + tmpArrOff++, b); } buf.position(pos + typeSize); } } /** * @param type Type. * @param val Value. * @param writer Writer. */ private void write(MessageCollectionItemType type, Object val, MessageWriter writer) { switch (type) { case BYTE: writeByte((Byte)val); break; case SHORT: writeShort((Short)val); break; case INT: writeInt((Integer)val); break; case LONG: writeLong((Long)val); break; case FLOAT: writeFloat((Float)val); break; case DOUBLE: writeDouble((Double)val); break; case CHAR: writeChar((Character)val); break; case BOOLEAN: writeBoolean((Boolean)val); break; case BYTE_ARR: writeByteArray((byte[])val); break; case SHORT_ARR: writeShortArray((short[])val); break; case INT_ARR: writeIntArray((int[])val); break; case LONG_ARR: writeLongArray((long[])val); break; case FLOAT_ARR: writeFloatArray((float[])val); break; case DOUBLE_ARR: writeDoubleArray((double[])val); break; case CHAR_ARR: writeCharArray((char[])val); break; case BOOLEAN_ARR: writeBooleanArray((boolean[])val); break; case STRING: writeString((String)val); break; case BIT_SET: writeBitSet((BitSet)val); break; case UUID: writeUuid((UUID)val); break; case IGNITE_UUID: writeIgniteUuid((IgniteUuid)val); break; case MSG: try { if (val != null) writer.beforeInnerMessageWrite(); writeMessage((Message)val, writer); } finally { if (val != null) writer.afterInnerMessageWrite(lastFinished); } break; default: throw new IllegalArgumentException("Unknown type: " + type); } } /** * @param type Type. * @param reader Reader. * @return Value. */ private Object read(MessageCollectionItemType type, MessageReader reader) { switch (type) { case BYTE: return readByte(); case SHORT: return readShort(); case INT: return readInt(); case LONG: return readLong(); case FLOAT: return readFloat(); case DOUBLE: return readDouble(); case CHAR: return readChar(); case BOOLEAN: return readBoolean(); case BYTE_ARR: return readByteArray(); case SHORT_ARR: return readShortArray(); case INT_ARR: return readIntArray(); case LONG_ARR: return readLongArray(); case FLOAT_ARR: return readFloatArray(); case DOUBLE_ARR: return readDoubleArray(); case CHAR_ARR: return readCharArray(); case BOOLEAN_ARR: return readBooleanArray(); case STRING: return readString(); case BIT_SET: return readBitSet(); case UUID: return readUuid(); case IGNITE_UUID: return readIgniteUuid(); case MSG: return readMessage(reader); default: throw new IllegalArgumentException("Unknown type: " + type); } } /** {@inheritDoc} */ @Override public String toString() { return S.toString(DirectByteBufferStreamImplV2.class, this); } /** * Array creator. */ private interface ArrayCreator<T> { /** * @param len Array length or {@code -1} if array was not fully read. * @return New array. */ public T create(int len); } }