http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java new file mode 100644 index 0000000..25f4d70 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java @@ -0,0 +1,1808 @@ +/* + * 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.binary; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.binary.BinaryIdMapper; +import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryRawWriter; +import org.apache.ignite.binary.BinaryWriter; +import org.apache.ignite.internal.binary.streams.PortableOutputStream; +import org.apache.ignite.internal.binary.streams.PortableHeapOutputStream; +import org.apache.ignite.internal.binary.streams.PortableOutputStream; +import org.apache.ignite.internal.util.typedef.internal.A; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.ObjectOutput; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.UUID; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.BOOLEAN; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.BOOLEAN_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.BYTE; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.BYTE_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.CHAR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.CHAR_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.CLASS; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.COL; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DATE; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DATE_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DECIMAL; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DECIMAL_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DFLT_HDR_LEN; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DOUBLE; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.DOUBLE_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.ENUM; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.ENUM_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.FLOAT; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.FLOAT_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.INT; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.INT_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.LONG; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.LONG_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.MAP; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.NULL; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.OBJ; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.OBJ_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.OPTM_MARSH; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.PORTABLE_OBJ; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.PROTO_VER; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.SHORT; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.SHORT_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.STRING; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.STRING_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.TIMESTAMP; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.TIMESTAMP_ARR; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.UNREGISTERED_TYPE_ID; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.UUID; +import static org.apache.ignite.internal.binary.GridPortableMarshaller.UUID_ARR; + +/** + * Portable writer implementation. + */ +public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, ObjectOutput { + /** Length: integer. */ + private static final int LEN_INT = 4; + + /** Initial capacity. */ + private static final int INIT_CAP = 1024; + + /** */ + private final PortableContext ctx; + + /** Output stream. */ + private final PortableOutputStream out; + + /** Schema. */ + private final BinaryWriterSchemaHolder schema; + + /** */ + private int typeId; + + /** */ + private final int start; + + /** Raw offset position. */ + private int rawOffPos; + + /** Handles. */ + private BinaryWriterHandles handles; + + /** Schema ID. */ + private int schemaId = PortableUtils.schemaInitialId(); + + /** Amount of written fields. */ + private int fieldCnt; + + /** ID mapper. */ + private BinaryIdMapper idMapper; + + /** + * @param ctx Context. + */ + public BinaryWriterExImpl(PortableContext ctx) { + this(ctx, BinaryThreadLocalContext.get()); + } + + /** + * @param ctx Context. + * @param tlsCtx TLS context. + */ + public BinaryWriterExImpl(PortableContext ctx, BinaryThreadLocalContext tlsCtx) { + this(ctx, new PortableHeapOutputStream(INIT_CAP, tlsCtx.chunk()), tlsCtx.schemaHolder(), null); + } + + /** + * @param ctx Context. + * @param out Output stream. + * @param handles Handles. + */ + public BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out, BinaryWriterSchemaHolder schema, + BinaryWriterHandles handles) { + this.ctx = ctx; + this.out = out; + this.schema = schema; + this.handles = handles; + + start = out.position(); + } + + /** + * @param typeId Type ID. + */ + public void typeId(int typeId) { + this.typeId = typeId; + } + + /** + * Close the writer releasing resources if necessary. + */ + @Override public void close() { + out.close(); + } + + /** + * @param obj Object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void marshal(Object obj) throws BinaryObjectException { + marshal(obj, true); + } + + /** + * @param obj Object. + * @param enableReplace Object replacing enabled flag. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void marshal(Object obj, boolean enableReplace) throws BinaryObjectException { + assert obj != null; + + Class<?> cls = obj.getClass(); + + PortableClassDescriptor desc = ctx.descriptorForClass(cls, false); + + if (desc == null) + throw new BinaryObjectException("Object is not portable: [class=" + cls + ']'); + + if (desc.excluded()) { + out.writeByte(GridPortableMarshaller.NULL); + + return; + } + + if (desc.useOptimizedMarshaller()) { + out.writeByte(GridPortableMarshaller.OPTM_MARSH); + + try { + byte[] arr = ctx.optimizedMarsh().marshal(obj); + + writeInt(arr.length); + + write(arr); + } + catch (IgniteCheckedException e) { + throw new BinaryObjectException("Failed to marshal object with optimized marshaller: " + obj, e); + } + + return; + } + + if (enableReplace && desc.getWriteReplaceMethod() != null) { + Object replacedObj; + + try { + replacedObj = desc.getWriteReplaceMethod().invoke(obj); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + if (e.getTargetException() instanceof BinaryObjectException) + throw (BinaryObjectException)e.getTargetException(); + + throw new BinaryObjectException("Failed to execute writeReplace() method on " + obj, e); + } + + if (replacedObj == null) { + out.writeByte(GridPortableMarshaller.NULL); + + return; + } + + marshal(replacedObj, false); + + return; + } + + desc.write(obj, this); + } + + /** + * @return Array. + */ + public byte[] array() { + return out.arrayCopy(); + } + + /** + * @return Stream current position. + */ + int position() { + return out.position(); + } + + /** + * Sets new position. + * + * @param pos Position. + */ + void position(int pos) { + out.position(pos); + } + + /** + * Perform pre-write. Reserves space for header and writes class name if needed. + * + * @param clsName Class name (optional). + */ + public void preWrite(@Nullable String clsName) { + out.position(out.position() + GridPortableMarshaller.DFLT_HDR_LEN); + + if (clsName != null) + doWriteString(clsName); + } + + /** + * Perform post-write. Fills object header. + * + * @param userType User type flag. + * @param registered Whether type is registered. + * @param hashCode Hash code. + */ + public void postWrite(boolean userType, boolean registered, int hashCode) { + short flags; + boolean useCompactFooter; + + if (userType) { + if (ctx.isCompactFooter()) { + flags = PortableUtils.FLAG_USR_TYP | PortableUtils.FLAG_COMPACT_FOOTER; + useCompactFooter = true; + } + else { + flags = PortableUtils.FLAG_USR_TYP; + useCompactFooter = false; + } + } + else { + flags = 0; + useCompactFooter = false; + } + + int finalSchemaId; + int offset; + + if (fieldCnt != 0) { + finalSchemaId = schemaId; + offset = out.position() - start; + + // Write the schema. + flags |= PortableUtils.FLAG_HAS_SCHEMA; + + int offsetByteCnt = schema.write(out, fieldCnt, useCompactFooter); + + if (offsetByteCnt == PortableUtils.OFFSET_1) + flags |= PortableUtils.FLAG_OFFSET_ONE_BYTE; + else if (offsetByteCnt == PortableUtils.OFFSET_2) + flags |= PortableUtils.FLAG_OFFSET_TWO_BYTES; + + // Write raw offset if needed. + if (rawOffPos != 0) { + flags |= PortableUtils.FLAG_HAS_RAW; + + out.writeInt(rawOffPos - start); + } + } + else { + if (rawOffPos != 0) { + finalSchemaId = 0; + offset = rawOffPos - start; + + // If there is no schema, we are free to write raw offset to schema offset. + flags |= PortableUtils.FLAG_HAS_RAW; + } + else { + finalSchemaId = 0; + offset = 0; + } + } + + // Actual write. + int retPos = out.position(); + + out.unsafePosition(start); + + out.unsafeWriteByte(GridPortableMarshaller.OBJ); + out.unsafeWriteByte(GridPortableMarshaller.PROTO_VER); + out.unsafeWriteShort(flags); + out.unsafeWriteInt(registered ? typeId : GridPortableMarshaller.UNREGISTERED_TYPE_ID); + out.unsafeWriteInt(hashCode); + out.unsafeWriteInt(retPos - start); + out.unsafeWriteInt(finalSchemaId); + out.unsafeWriteInt(offset); + + out.unsafePosition(retPos); + } + + /** + * Pop schema. + */ + public void popSchema() { + if (fieldCnt > 0) + schema.pop(fieldCnt); + } + + /** + * @param val Byte array. + */ + public void write(byte[] val) { + assert val != null; + + out.writeByteArray(val); + } + + /** + * @param val Byte array. + * @param off Offset. + * @param len Length. + */ + public void write(byte[] val, int off, int len) { + assert val != null; + + out.write(val, off, len); + } + + /** + * @param val String value. + */ + public void doWriteDecimal(@Nullable BigDecimal val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.DECIMAL); + + BigInteger intVal = val.unscaledValue(); + + if (intVal.signum() == -1) { + intVal = intVal.negate(); + + out.unsafeWriteInt(val.scale() | 0x80000000); + } + else + out.unsafeWriteInt(val.scale()); + + byte[] vals = intVal.toByteArray(); + + out.unsafeWriteInt(vals.length); + out.writeByteArray(vals); + } + } + + /** + * @param val String value. + */ + public void doWriteString(@Nullable String val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + byte[] strArr = val.getBytes(UTF_8); + + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.STRING); + out.unsafeWriteInt(strArr.length); + + out.writeByteArray(strArr); + } + } + + /** + * @param uuid UUID. + */ + public void doWriteUuid(@Nullable UUID uuid) { + if (uuid == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 8 + 8); + out.unsafeWriteByte(GridPortableMarshaller.UUID); + out.unsafeWriteLong(uuid.getMostSignificantBits()); + out.unsafeWriteLong(uuid.getLeastSignificantBits()); + } + } + + /** + * @param date Date. + */ + public void doWriteDate(@Nullable Date date) { + if (date == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 8); + out.unsafeWriteByte(GridPortableMarshaller.DATE); + out.unsafeWriteLong(date.getTime()); + } + } + + /** + * @param ts Timestamp. + */ + public void doWriteTimestamp(@Nullable Timestamp ts) { + if (ts== null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 8 + 4); + out.unsafeWriteByte(GridPortableMarshaller.TIMESTAMP); + out.unsafeWriteLong(ts.getTime()); + out.unsafeWriteInt(ts.getNanos() % 1000000); + } + } + + /** + * Write object. + * + * @param obj Object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + public void doWriteObject(@Nullable Object obj) throws BinaryObjectException { + if (obj == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, schema, handles()); + + writer.marshal(obj); + } + } + + /** + * @param val Byte array. + */ + void doWriteByteArray(@Nullable byte[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.BYTE_ARR); + out.unsafeWriteInt(val.length); + + out.writeByteArray(val); + } + } + + /** + * @param val Short array. + */ + void doWriteShortArray(@Nullable short[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.SHORT_ARR); + out.unsafeWriteInt(val.length); + + out.writeShortArray(val); + } + } + + /** + * @param val Integer array. + */ + void doWriteIntArray(@Nullable int[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.INT_ARR); + out.unsafeWriteInt(val.length); + + out.writeIntArray(val); + } + } + + /** + * @param val Long array. + */ + void doWriteLongArray(@Nullable long[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.LONG_ARR); + out.unsafeWriteInt(val.length); + + out.writeLongArray(val); + } + } + + /** + * @param val Float array. + */ + void doWriteFloatArray(@Nullable float[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.FLOAT_ARR); + out.unsafeWriteInt(val.length); + + out.writeFloatArray(val); + } + } + + /** + * @param val Double array. + */ + void doWriteDoubleArray(@Nullable double[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.DOUBLE_ARR); + out.unsafeWriteInt(val.length); + + out.writeDoubleArray(val); + } + } + + /** + * @param val Char array. + */ + void doWriteCharArray(@Nullable char[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.CHAR_ARR); + out.unsafeWriteInt(val.length); + + out.writeCharArray(val); + } + } + + /** + * @param val Boolean array. + */ + void doWriteBooleanArray(@Nullable boolean[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.BOOLEAN_ARR); + out.unsafeWriteInt(val.length); + + out.writeBooleanArray(val); + } + } + + /** + * @param val Array of strings. + */ + void doWriteDecimalArray(@Nullable BigDecimal[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.DECIMAL_ARR); + out.unsafeWriteInt(val.length); + + for (BigDecimal str : val) + doWriteDecimal(str); + } + } + + /** + * @param val Array of strings. + */ + void doWriteStringArray(@Nullable String[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.STRING_ARR); + out.unsafeWriteInt(val.length); + + for (String str : val) + doWriteString(str); + } + } + + /** + * @param val Array of UUIDs. + */ + void doWriteUuidArray(@Nullable UUID[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.UUID_ARR); + out.unsafeWriteInt(val.length); + + for (UUID uuid : val) + doWriteUuid(uuid); + } + } + + /** + * @param val Array of dates. + */ + void doWriteDateArray(@Nullable Date[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.DATE_ARR); + out.unsafeWriteInt(val.length); + + for (Date date : val) + doWriteDate(date); + } + } + + /** + * @param val Array of timestamps. + */ + void doWriteTimestampArray(@Nullable Timestamp[] val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.TIMESTAMP_ARR); + out.unsafeWriteInt(val.length); + + for (Timestamp ts : val) + doWriteTimestamp(ts); + } + } + + /** + * @param val Array of objects. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void doWriteObjectArray(@Nullable Object[] val) throws BinaryObjectException { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + if (tryWriteAsHandle(val)) + return; + + PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType(), false); + + out.unsafeEnsure(1 + 4); + out.unsafeWriteByte(GridPortableMarshaller.OBJ_ARR); + + if (desc.registered()) + out.unsafeWriteInt(desc.typeId()); + else { + out.unsafeWriteInt(GridPortableMarshaller.UNREGISTERED_TYPE_ID); + + doWriteString(val.getClass().getComponentType().getName()); + } + + out.writeInt(val.length); + + for (Object obj : val) + doWriteObject(obj); + } + } + + /** + * @param col Collection. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void doWriteCollection(@Nullable Collection<?> col) throws BinaryObjectException { + if (col == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + if (tryWriteAsHandle(col)) + return; + + out.unsafeEnsure(1 + 4 + 1); + out.unsafeWriteByte(GridPortableMarshaller.COL); + out.unsafeWriteInt(col.size()); + out.unsafeWriteByte(ctx.collectionType(col.getClass())); + + for (Object obj : col) + doWriteObject(obj); + } + } + + /** + * @param map Map. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void doWriteMap(@Nullable Map<?, ?> map) throws BinaryObjectException { + if (map == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + if (tryWriteAsHandle(map)) + return; + + out.unsafeEnsure(1 + 4 + 1); + out.unsafeWriteByte(GridPortableMarshaller.MAP); + out.unsafeWriteInt(map.size()); + out.unsafeWriteByte(ctx.mapType(map.getClass())); + + for (Map.Entry<?, ?> e : map.entrySet()) { + doWriteObject(e.getKey()); + doWriteObject(e.getValue()); + } + } + } + + /** + * @param val Value. + */ + void doWriteEnum(@Nullable Enum<?> val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass(), false); + + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.ENUM); + + if (desc.registered()) + out.unsafeWriteInt(desc.typeId()); + else { + out.unsafeWriteInt(GridPortableMarshaller.UNREGISTERED_TYPE_ID); + doWriteString(val.getClass().getName()); + } + + out.writeInt(val.ordinal()); + } + } + + /** + * @param val Value. + */ + void doWritePortableEnum(BinaryEnumObjectImpl val) { + assert val != null; + + int typeId = val.typeId(); + + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.ENUM); + out.unsafeWriteInt(typeId); + + if (typeId == GridPortableMarshaller.UNREGISTERED_TYPE_ID) + doWriteString(val.className()); + + out.writeInt(val.enumOrdinal()); + } + + /** + * @param val Array. + */ + void doWriteEnumArray(@Nullable Object[] val) { + assert val == null || val.getClass().getComponentType().isEnum(); + + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType(), false); + + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.ENUM_ARR); + + if (desc.registered()) + out.unsafeWriteInt(desc.typeId()); + else { + out.unsafeWriteInt(GridPortableMarshaller.UNREGISTERED_TYPE_ID); + + doWriteString(val.getClass().getComponentType().getName()); + } + + out.writeInt(val.length); + + // TODO: Denis: Redundant data for each element of the array. + for (Object o : val) + doWriteEnum((Enum<?>)o); + } + } + + /** + * @param val Class. + */ + void doWriteClass(@Nullable Class val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + PortableClassDescriptor desc = ctx.descriptorForClass(val, false); + + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.CLASS); + + if (desc.registered()) + out.unsafeWriteInt(desc.typeId()); + else { + out.unsafeWriteInt(GridPortableMarshaller.UNREGISTERED_TYPE_ID); + + doWriteString(val.getClass().getName()); + } + } + } + + /** + * @param po Portable object. + */ + public void doWritePortableObject(@Nullable BinaryObjectImpl po) { + if (po == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + byte[] poArr = po.array(); + + out.unsafeEnsure(1 + 4 + poArr.length + 4); + + out.unsafeWriteByte(GridPortableMarshaller.PORTABLE_OBJ); + out.unsafeWriteInt(poArr.length); + out.writeByteArray(poArr); + out.unsafeWriteInt(po.start()); + } + } + + /** + * @param val Value. + */ + void writeByteFieldPrimitive(byte val) { + out.unsafeEnsure(1 + 1); + + out.unsafeWriteByte(GridPortableMarshaller.BYTE); + out.unsafeWriteByte(val); + } + + /** + * @param val Value. + */ + void writeByteField(@Nullable Byte val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeByteFieldPrimitive(val); + } + + /** + * @param val Class. + */ + void writeClassField(@Nullable Class val) { + doWriteClass(val); + } + + /** + * @param val Value. + */ + void writeShortFieldPrimitive(short val) { + out.unsafeEnsure(1 + 2); + + out.unsafeWriteByte(GridPortableMarshaller.SHORT); + out.unsafeWriteShort(val); + } + + /** + * @param val Value. + */ + void writeShortField(@Nullable Short val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeShortFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeIntFieldPrimitive(int val) { + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.INT); + out.unsafeWriteInt(val); + } + + /** + * @param val Value. + */ + void writeIntField(@Nullable Integer val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeIntFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeLongFieldPrimitive(long val) { + out.unsafeEnsure(1 + 8); + + out.unsafeWriteByte(GridPortableMarshaller.LONG); + out.unsafeWriteLong(val); + } + + /** + * @param val Value. + */ + void writeLongField(@Nullable Long val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeLongFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeFloatFieldPrimitive(float val) { + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.FLOAT); + out.unsafeWriteFloat(val); + } + + /** + * @param val Value. + */ + void writeFloatField(@Nullable Float val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeFloatFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeDoubleFieldPrimitive(double val) { + out.unsafeEnsure(1 + 8); + + out.unsafeWriteByte(GridPortableMarshaller.DOUBLE); + out.unsafeWriteDouble(val); + } + + /** + * @param val Value. + */ + void writeDoubleField(@Nullable Double val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeDoubleFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeCharFieldPrimitive(char val) { + out.unsafeEnsure(1 + 2); + + out.unsafeWriteByte(GridPortableMarshaller.CHAR); + out.unsafeWriteChar(val); + } + + /** + * @param val Value. + */ + void writeCharField(@Nullable Character val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeCharFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeBooleanFieldPrimitive(boolean val) { + out.unsafeEnsure(1 + 1); + + out.unsafeWriteByte(GridPortableMarshaller.BOOLEAN); + out.unsafeWriteBoolean(val); + } + + /** + * @param val Value. + */ + void writeBooleanField(@Nullable Boolean val) { + if (val == null) + out.writeByte(GridPortableMarshaller.NULL); + else + writeBooleanFieldPrimitive(val); + } + + /** + * @param val Value. + */ + void writeDecimalField(@Nullable BigDecimal val) { + doWriteDecimal(val); + } + + /** + * @param val Value. + */ + void writeStringField(@Nullable String val) { + doWriteString(val); + } + + /** + * @param val Value. + */ + void writeUuidField(@Nullable UUID val) { + doWriteUuid(val); + } + + /** + * @param val Value. + */ + void writeDateField(@Nullable Date val) { + doWriteDate(val); + } + + /** + * @param val Value. + */ + void writeTimestampField(@Nullable Timestamp val) { + doWriteTimestamp(val); + } + + /** + * @param obj Object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void writeObjectField(@Nullable Object obj) throws BinaryObjectException { + doWriteObject(obj); + } + + /** + * @param val Value. + */ + void writeByteArrayField(@Nullable byte[] val) { + doWriteByteArray(val); + } + + /** + * @param val Value. + */ + void writeShortArrayField(@Nullable short[] val) { + doWriteShortArray(val); + } + + /** + * @param val Value. + */ + void writeIntArrayField(@Nullable int[] val) { + doWriteIntArray(val); + } + + /** + * @param val Value. + */ + void writeLongArrayField(@Nullable long[] val) { + doWriteLongArray(val); + } + + /** + * @param val Value. + */ + void writeFloatArrayField(@Nullable float[] val) { + doWriteFloatArray(val); + } + + /** + * @param val Value. + */ + void writeDoubleArrayField(@Nullable double[] val) { + doWriteDoubleArray(val); + } + + /** + * @param val Value. + */ + void writeCharArrayField(@Nullable char[] val) { + doWriteCharArray(val); + } + + /** + * @param val Value. + */ + void writeBooleanArrayField(@Nullable boolean[] val) { + doWriteBooleanArray(val); + } + + /** + * @param val Value. + */ + void writeDecimalArrayField(@Nullable BigDecimal[] val) { + doWriteDecimalArray(val); + } + + /** + * @param val Value. + */ + void writeStringArrayField(@Nullable String[] val) { + doWriteStringArray(val); + } + + /** + * @param val Value. + */ + void writeUuidArrayField(@Nullable UUID[] val) { + doWriteUuidArray(val); + } + + /** + * @param val Value. + */ + void writeDateArrayField(@Nullable Date[] val) { + doWriteDateArray(val); + } + + /** + * @param val Value. + */ + void writeTimestampArrayField(@Nullable Timestamp[] val) { + doWriteTimestampArray(val); + } + + /** + * @param val Value. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void writeObjectArrayField(@Nullable Object[] val) throws BinaryObjectException { + doWriteObjectArray(val); + } + + /** + * @param col Collection. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void writeCollectionField(@Nullable Collection<?> col) throws BinaryObjectException { + doWriteCollection(col); + } + + /** + * @param map Map. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void writeMapField(@Nullable Map<?, ?> map) throws BinaryObjectException { + doWriteMap(map); + } + + /** + * @param val Value. + */ + void writeEnumField(@Nullable Enum<?> val) { + doWriteEnum(val); + } + + /** + * @param val Value. + */ + void writeEnumArrayField(@Nullable Object[] val) { + doWriteEnumArray(val); + } + + /** + * @param po Portable object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + void writePortableObjectField(@Nullable BinaryObjectImpl po) throws BinaryObjectException { + doWritePortableObject(po); + } + + /** {@inheritDoc} */ + @Override public void writeByte(String fieldName, byte val) throws BinaryObjectException { + writeFieldId(fieldName); + writeByteField(val); + } + + /** {@inheritDoc} */ + @Override public void writeByte(byte val) throws BinaryObjectException { + out.writeByte(val); + } + + /** {@inheritDoc} */ + @Override public void writeShort(String fieldName, short val) throws BinaryObjectException { + writeFieldId(fieldName); + writeShortField(val); + } + + /** {@inheritDoc} */ + @Override public void writeShort(short val) throws BinaryObjectException { + out.writeShort(val); + } + + /** {@inheritDoc} */ + @Override public void writeInt(String fieldName, int val) throws BinaryObjectException { + writeFieldId(fieldName); + writeIntField(val); + } + + /** {@inheritDoc} */ + @Override public void writeInt(int val) throws BinaryObjectException { + out.writeInt(val); + } + + /** {@inheritDoc} */ + @Override public void writeLong(String fieldName, long val) throws BinaryObjectException { + writeFieldId(fieldName); + writeLongField(val); + } + + /** {@inheritDoc} */ + @Override public void writeLong(long val) throws BinaryObjectException { + out.writeLong(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(String fieldName, float val) throws BinaryObjectException { + writeFieldId(fieldName); + writeFloatField(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(float val) throws BinaryObjectException { + out.writeFloat(val); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(String fieldName, double val) throws BinaryObjectException { + writeFieldId(fieldName); + writeDoubleField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(double val) throws BinaryObjectException { + out.writeDouble(val); + } + + /** {@inheritDoc} */ + @Override public void writeChar(String fieldName, char val) throws BinaryObjectException { + writeFieldId(fieldName); + writeCharField(val); + } + + /** {@inheritDoc} */ + @Override public void writeChar(char val) throws BinaryObjectException { + out.writeChar(val); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(String fieldName, boolean val) throws BinaryObjectException { + writeFieldId(fieldName); + writeBooleanField(val); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(boolean val) throws BinaryObjectException { + out.writeBoolean(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws BinaryObjectException { + writeFieldId(fieldName); + writeDecimalField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimal(@Nullable BigDecimal val) throws BinaryObjectException { + doWriteDecimal(val); + } + + /** {@inheritDoc} */ + @Override public void writeString(String fieldName, @Nullable String val) throws BinaryObjectException { + writeFieldId(fieldName); + writeStringField(val); + } + + /** {@inheritDoc} */ + @Override public void writeString(@Nullable String val) throws BinaryObjectException { + doWriteString(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuid(String fieldName, @Nullable UUID val) throws BinaryObjectException { + writeFieldId(fieldName); + writeUuidField(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuid(@Nullable UUID val) throws BinaryObjectException { + doWriteUuid(val); + } + + /** {@inheritDoc} */ + @Override public void writeDate(String fieldName, @Nullable Date val) throws BinaryObjectException { + writeFieldId(fieldName); + writeDateField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDate(@Nullable Date val) throws BinaryObjectException { + doWriteDate(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws BinaryObjectException { + writeFieldId(fieldName); + writeTimestampField(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestamp(@Nullable Timestamp val) throws BinaryObjectException { + doWriteTimestamp(val); + } + + /** {@inheritDoc} */ + @Override public void writeObject(String fieldName, @Nullable Object obj) throws BinaryObjectException { + writeFieldId(fieldName); + writeObjectField(obj); + } + + /** {@inheritDoc} */ + @Override public void writeObject(@Nullable Object obj) throws BinaryObjectException { + doWriteObject(obj); + } + + /** {@inheritDoc} */ + @Override public void writeObjectDetached(@Nullable Object obj) throws BinaryObjectException { + if (obj == null) + out.writeByte(GridPortableMarshaller.NULL); + else { + BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, schema, null); + + writer.marshal(obj); + } + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeByteArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(@Nullable byte[] val) throws BinaryObjectException { + doWriteByteArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeShortArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(@Nullable short[] val) throws BinaryObjectException { + doWriteShortArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeIntArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(@Nullable int[] val) throws BinaryObjectException { + doWriteIntArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeLongArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(@Nullable long[] val) throws BinaryObjectException { + doWriteLongArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeFloatArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(@Nullable float[] val) throws BinaryObjectException { + doWriteFloatArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) + throws BinaryObjectException { + writeFieldId(fieldName); + writeDoubleArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(@Nullable double[] val) throws BinaryObjectException { + doWriteDoubleArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeCharArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(@Nullable char[] val) throws BinaryObjectException { + doWriteCharArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) + throws BinaryObjectException { + writeFieldId(fieldName); + writeBooleanArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(@Nullable boolean[] val) throws BinaryObjectException { + doWriteBooleanArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val) + throws BinaryObjectException { + writeFieldId(fieldName); + writeDecimalArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimalArray(@Nullable BigDecimal[] val) throws BinaryObjectException { + doWriteDecimalArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(String fieldName, @Nullable String[] val) + throws BinaryObjectException { + writeFieldId(fieldName); + writeStringArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(@Nullable String[] val) throws BinaryObjectException { + doWriteStringArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeUuidArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuidArray(@Nullable UUID[] val) throws BinaryObjectException { + doWriteUuidArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeDateArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDateArray(@Nullable Date[] val) throws BinaryObjectException { + doWriteDateArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeTimestampArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestampArray(@Nullable Timestamp[] val) throws BinaryObjectException { + doWriteTimestampArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeObjectArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(@Nullable Object[] val) throws BinaryObjectException { + doWriteObjectArray(val); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) + throws BinaryObjectException { + writeFieldId(fieldName); + writeCollectionField(col); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(@Nullable Collection<T> col) throws BinaryObjectException { + doWriteCollection(col); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) + throws BinaryObjectException { + writeFieldId(fieldName); + writeMapField(map); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(@Nullable Map<K, V> map) throws BinaryObjectException { + doWriteMap(map); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws BinaryObjectException { + writeFieldId(fieldName); + writeEnumField(val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(T val) throws BinaryObjectException { + doWriteEnum(val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws BinaryObjectException { + writeFieldId(fieldName); + writeEnumArrayField(val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(T[] val) throws BinaryObjectException { + doWriteEnumArray(val); + } + + /** {@inheritDoc} */ + @Override public BinaryRawWriter rawWriter() { + if (rawOffPos == 0) + rawOffPos = out.position(); + + return this; + } + + /** {@inheritDoc} */ + @Override public PortableOutputStream out() { + return out; + } + + /** {@inheritDoc} */ + @SuppressWarnings("NullableProblems") + @Override public void writeBytes(String s) throws IOException { + int len = s.length(); + + writeInt(len); + + for (int i = 0; i < len; i++) + writeByte(s.charAt(i)); + } + + /** {@inheritDoc} */ + @SuppressWarnings("NullableProblems") + @Override public void writeChars(String s) throws IOException { + int len = s.length(); + + writeInt(len); + + for (int i = 0; i < len; i++) + writeChar(s.charAt(i)); + } + + /** {@inheritDoc} */ + @SuppressWarnings("NullableProblems") + @Override public void writeUTF(String s) throws IOException { + writeString(s); + } + + /** {@inheritDoc} */ + @Override public void writeByte(int v) throws IOException { + out.writeByte((byte) v); + } + + /** {@inheritDoc} */ + @Override public void writeShort(int v) throws IOException { + out.writeShort((short) v); + } + + /** {@inheritDoc} */ + @Override public void writeChar(int v) throws IOException { + out.writeChar((char) v); + } + + /** {@inheritDoc} */ + @Override public void write(int b) throws IOException { + out.writeByte((byte) b); + } + + /** {@inheritDoc} */ + @Override public void flush() throws IOException { + // No-op. + } + + /** {@inheritDoc} */ + @Override public int reserveInt() { + int pos = out.position(); + + out.position(pos + LEN_INT); + + return pos; + } + + /** {@inheritDoc} */ + @Override public void writeInt(int pos, int val) throws BinaryObjectException { + out.writeInt(pos, val); + } + + /** + * @param fieldName Field name. + * @throws org.apache.ignite.binary.BinaryObjectException If fields are not allowed. + */ + private void writeFieldId(String fieldName) throws BinaryObjectException { + A.notNull(fieldName, "fieldName"); + + if (rawOffPos != 0) + throw new BinaryObjectException("Individual field can't be written after raw writer is acquired."); + + if (idMapper == null) + idMapper = ctx.userTypeIdMapper(typeId); + + int id = idMapper.fieldId(typeId, fieldName); + + writeFieldId(id); + } + + /** + * Write field ID. + * @param fieldId Field ID. + */ + public void writeFieldId(int fieldId) { + int fieldOff = out.position() - start; + + // Advance schema hash. + schemaId = PortableUtils.updateSchemaId(schemaId, fieldId); + + schema.push(fieldId, fieldOff); + + fieldCnt++; + } + + /** + * Write field ID without schema ID update. This method should be used when schema ID is stable because class + * is seializable. + * + * @param fieldId Field ID. + */ + public void writeFieldIdNoSchemaUpdate(int fieldId) { + int fieldOff = out.position() - start; + + schema.push(fieldId, fieldOff); + + fieldCnt++; + } + + /** + * @param schemaId Schema ID. + */ + public void schemaId(int schemaId) { + this.schemaId = schemaId; + } + + /** + * @return Schema ID. + */ + public int schemaId() { + return schemaId; + } + + /** + * @return Current writer's schema. + */ + public PortableSchema currentSchema() { + PortableSchema.Builder builder = PortableSchema.Builder.newBuilder(); + + if (schema != null) + schema.build(builder, fieldCnt); + + return builder.build(); + } + + /** + * Get current handles. If they are {@code null}, then we should create them. Otherwise we will not see updates + * performed by child writers. + * + * @return Handles. + */ + private BinaryWriterHandles handles() { + if (handles == null) + handles = new BinaryWriterHandles(); + + return handles; + } + + /** + * Attempts to write the object as a handle. + * + * @param obj Object to write. + * @return {@code true} if the object has been written as a handle. + */ + boolean tryWriteAsHandle(Object obj) { + assert obj != null; + + int pos = out.position(); + + BinaryWriterHandles handles0 = handles(); + + int old = handles0.put(obj, pos); + + if (old == BinaryWriterHandles.POS_NULL) + return false; + else { + out.unsafeEnsure(1 + 4); + + out.unsafeWriteByte(GridPortableMarshaller.HANDLE); + out.unsafeWriteInt(pos - old); + + return true; + } + } + + /** + * Create new writer with same context. + * + * @param typeId type + * @return New writer. + */ + public BinaryWriterExImpl newWriter(int typeId) { + BinaryWriterExImpl res = new BinaryWriterExImpl(ctx, out, schema, handles()); + + res.typeId(typeId); + + return res; + } + + /** + * @return Portable context. + */ + public PortableContext context() { + return ctx; + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterHandles.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterHandles.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterHandles.java new file mode 100644 index 0000000..3be3898 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterHandles.java @@ -0,0 +1,101 @@ +/* + * 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.binary; + +import java.util.IdentityHashMap; + +/** + * Writer handles. Aimed to delay hash map allocation for some time until it is clearly evident that it is needed. + */ +public class BinaryWriterHandles { + /** Value denoting null position. */ + public static final int POS_NULL = -1; + + /** Mode: empty. */ + private static final int MODE_EMPTY = 0; + + /** Mode: single object. */ + private static final int MODE_SINGLE = 1; + + /** Mode: multiple objects. */ + private static final int MODE_MULTIPLE = 2; + + /** Data. This is either an object or a map. */ + private Object data; + + /** Position. */ + private int singlePos; + + /** Mode. */ + private int mode = MODE_EMPTY; + + /** + * Put object to registry and return previous position (if any). + * + * @param obj Object. + * @param pos Position. + * @return Old position. + */ + @SuppressWarnings("unchecked") + public int put(Object obj, int pos) { + assert obj != null; + assert pos >= 0; + + switch (mode) { + case MODE_EMPTY: + this.data = obj; + this.singlePos = pos; + this.mode = MODE_SINGLE; + + return POS_NULL; + + case MODE_SINGLE: + if (this.data == obj) + return singlePos; + else { + IdentityHashMap<Object, Integer> newData = new IdentityHashMap<>(2); + + newData.put(data, singlePos); + newData.put(obj, pos); + + this.data = newData; + this.singlePos = -1; + this.mode = MODE_MULTIPLE; + + return POS_NULL; + } + + default: + assert mode == MODE_MULTIPLE; + + IdentityHashMap<Object, Integer> data0 = (IdentityHashMap<Object, Integer>)data; + + Integer oldPos = data0.put(obj, pos); + + if (oldPos != null) { + // Restore initial position and return it. + data0.put(obj, oldPos); + + return oldPos; + } + else + return POS_NULL; + + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterSchemaHolder.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterSchemaHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterSchemaHolder.java new file mode 100644 index 0000000..7fd6442 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterSchemaHolder.java @@ -0,0 +1,149 @@ +/* + * 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.binary; + +import org.apache.ignite.internal.binary.streams.PortableOutputStream; +import org.apache.ignite.internal.binary.streams.PortableOutputStream; + +/** + * Binary writer schema holder. + */ +public class BinaryWriterSchemaHolder { + /** Maximum offset which fits in 1 byte. */ + private static final int MAX_OFFSET_1 = 1 << 8; + + /** Maximum offset which fits in 2 bytes. */ + private static final int MAX_OFFSET_2 = 1 << 16; + + /** Grow step. */ + private static final int GROW_STEP = 64; + + /** Data. */ + private int[] data = new int[GROW_STEP]; + + /** Index. */ + private int idx; + + /** + * Push another frame. + * + * @param id Field ID. + * @param off Field offset. + */ + public void push(int id, int off) { + if (idx == data.length) { + int[] data0 = new int[data.length + GROW_STEP]; + + System.arraycopy(data, 0, data0, 0, data.length); + + data = data0; + } + + data[idx] = id; + data[idx + 1] = off; + + idx += 2; + } + + /** + * Build the schema. + * + * @param builder Builder. + * @param fieldCnt Fields count. + */ + public void build(PortableSchema.Builder builder, int fieldCnt) { + for (int curIdx = idx - fieldCnt * 2; curIdx < idx; curIdx += 2) + builder.addField(data[curIdx]); + } + + /** + * Write collected frames and pop them. + * + * @param out Output stream. + * @param fieldCnt Count. + * @param compactFooter Whether footer should be written in compact form. + * @return Amount of bytes dedicated to each field offset. Could be 1, 2 or 4. + */ + public int write(PortableOutputStream out, int fieldCnt, boolean compactFooter) { + int startIdx = idx - fieldCnt * 2; + assert startIdx >= 0; + + // Ensure there are at least 8 bytes for each field to allow for unsafe writes. + out.unsafeEnsure(fieldCnt << 3); + + int lastOffset = data[idx - 1]; + + int res; + + if (compactFooter) { + if (lastOffset < MAX_OFFSET_1) { + for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2) + out.unsafeWriteByte((byte)data[curIdx]); + + res = PortableUtils.OFFSET_1; + } + else if (lastOffset < MAX_OFFSET_2) { + for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2) + out.unsafeWriteShort((short) data[curIdx]); + + res = PortableUtils.OFFSET_2; + } + else { + for (int curIdx = startIdx + 1; curIdx < idx; curIdx += 2) + out.unsafeWriteInt(data[curIdx]); + + res = PortableUtils.OFFSET_4; + } + } + else { + if (lastOffset < MAX_OFFSET_1) { + for (int curIdx = startIdx; curIdx < idx;) { + out.unsafeWriteInt(data[curIdx++]); + out.unsafeWriteByte((byte) data[curIdx++]); + } + + res = PortableUtils.OFFSET_1; + } + else if (lastOffset < MAX_OFFSET_2) { + for (int curIdx = startIdx; curIdx < idx;) { + out.unsafeWriteInt(data[curIdx++]); + out.unsafeWriteShort((short) data[curIdx++]); + } + + res = PortableUtils.OFFSET_2; + } + else { + for (int curIdx = startIdx; curIdx < idx;) { + out.unsafeWriteInt(data[curIdx++]); + out.unsafeWriteInt(data[curIdx++]); + } + + res = PortableUtils.OFFSET_4; + } + } + + return res; + } + + /** + * Pop current object's frame. + */ + public void pop(int fieldCnt) { + idx = idx - fieldCnt * 2; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/GridPortableMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridPortableMarshaller.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridPortableMarshaller.java new file mode 100644 index 0000000..a57bb55 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridPortableMarshaller.java @@ -0,0 +1,289 @@ +/* + * 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.binary; + +import org.apache.ignite.internal.binary.streams.PortableHeapInputStream; +import org.apache.ignite.internal.binary.streams.PortableInputStream; +import org.apache.ignite.internal.binary.streams.PortableOutputStream; +import org.apache.ignite.internal.binary.streams.PortableHeapInputStream; +import org.apache.ignite.internal.binary.streams.PortableInputStream; +import org.apache.ignite.internal.binary.streams.PortableOutputStream; +import org.apache.ignite.binary.BinaryObjectException; +import org.jetbrains.annotations.Nullable; + +/** + * Portable objects marshaller. + */ +public class GridPortableMarshaller { + /** */ + public static final ThreadLocal<Boolean> KEEP_PORTABLES = new ThreadLocal<Boolean>() { + @Override protected Boolean initialValue() { + return true; + } + }; + + /** */ + static final byte OPTM_MARSH = -2; + + /** */ + public static final byte BYTE = 1; + + /** */ + public static final byte SHORT = 2; + + /** */ + public static final byte INT = 3; + + /** */ + public static final byte LONG = 4; + + /** */ + public static final byte FLOAT = 5; + + /** */ + public static final byte DOUBLE = 6; + + /** */ + public static final byte CHAR = 7; + + /** */ + public static final byte BOOLEAN = 8; + + /** */ + public static final byte DECIMAL = 30; + + /** */ + public static final byte STRING = 9; + + /** */ + public static final byte UUID = 10; + + /** */ + public static final byte DATE = 11; + + /** */ + public static final byte BYTE_ARR = 12; + + /** */ + public static final byte SHORT_ARR = 13; + + /** */ + public static final byte INT_ARR = 14; + + /** */ + public static final byte LONG_ARR = 15; + + /** */ + public static final byte FLOAT_ARR = 16; + + /** */ + public static final byte DOUBLE_ARR = 17; + + /** */ + public static final byte CHAR_ARR = 18; + + /** */ + public static final byte BOOLEAN_ARR = 19; + + /** */ + public static final byte DECIMAL_ARR = 31; + + /** */ + public static final byte STRING_ARR = 20; + + /** */ + public static final byte UUID_ARR = 21; + + /** */ + public static final byte DATE_ARR = 22; + + /** */ + public static final byte OBJ_ARR = 23; + + /** */ + public static final byte COL = 24; + + /** */ + public static final byte MAP = 25; + + /** */ + public static final byte PORTABLE_OBJ = 27; + + /** */ + public static final byte ENUM = 28; + + /** */ + public static final byte ENUM_ARR = 29; + + /** */ + public static final byte CLASS = 32; + + /** Timestamp. */ + public static final byte TIMESTAMP = 33; + + /** Timestamp array. */ + public static final byte TIMESTAMP_ARR = 34; + + /** */ + public static final byte NULL = (byte)101; + + /** */ + public static final byte HANDLE = (byte)102; + + /** */ + public static final byte OBJ = (byte)103; + + /** */ + public static final byte USER_SET = -1; + + /** */ + public static final byte USER_COL = 0; + + /** */ + public static final byte ARR_LIST = 1; + + /** */ + public static final byte LINKED_LIST = 2; + + /** */ + public static final byte HASH_SET = 3; + + /** */ + public static final byte LINKED_HASH_SET = 4; + + /** */ + public static final byte HASH_MAP = 1; + + /** */ + public static final byte LINKED_HASH_MAP = 2; + + /** */ + public static final int OBJECT_TYPE_ID = -1; + + /** */ + public static final int UNREGISTERED_TYPE_ID = 0; + + /** Protocol version. */ + public static final byte PROTO_VER = 1; + + /** Protocol version position. */ + public static final int PROTO_VER_POS = 1; + + /** Flags position in header. */ + public static final int FLAGS_POS = 2; + + /** */ + public static final int TYPE_ID_POS = 4; + + /** */ + public static final int HASH_CODE_POS = 8; + + /** */ + public static final int TOTAL_LEN_POS = 12; + + /** */ + public static final int SCHEMA_ID_POS = 16; + + /** Schema or raw offset position. */ + public static final int SCHEMA_OR_RAW_OFF_POS = 20; + + /** */ + public static final byte DFLT_HDR_LEN = 24; + + /** */ + private final PortableContext ctx; + + /** + * @param ctx Context. + */ + public GridPortableMarshaller(PortableContext ctx) { + this.ctx = ctx; + } + + /** + * @param obj Object to marshal. + * @return Byte array. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + public byte[] marshal(@Nullable Object obj) throws BinaryObjectException { + if (obj == null) + return new byte[] { NULL }; + + try (BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx)) { + writer.marshal(obj); + + return writer.array(); + } + } + + /** + * @param bytes Bytes array. + * @return Portable object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + @SuppressWarnings("unchecked") + @Nullable public <T> T unmarshal(byte[] bytes, @Nullable ClassLoader clsLdr) throws BinaryObjectException { + assert bytes != null; + + return (T)PortableUtils.unmarshal(PortableHeapInputStream.create(bytes, 0), ctx, clsLdr); + } + + /** + * @param in Input stream. + * @return Portable object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + @SuppressWarnings("unchecked") + @Nullable public <T> T unmarshal(PortableInputStream in) throws BinaryObjectException { + return (T)PortableUtils.unmarshal(in, ctx, null); + } + + /** + * @param arr Byte array. + * @param ldr Class loader. + * @return Deserialized object. + * @throws org.apache.ignite.binary.BinaryObjectException In case of error. + */ + @SuppressWarnings("unchecked") + @Nullable public <T> T deserialize(byte[] arr, @Nullable ClassLoader ldr) throws BinaryObjectException { + assert arr != null; + assert arr.length > 0; + + if (arr[0] == NULL) + return null; + + return (T)new BinaryReaderExImpl(ctx, PortableHeapInputStream.create(arr, 0), ldr).deserialize(); + } + + /** + * Gets writer for the given output stream. + * + * @param out Output stream. + * @return Writer. + */ + public BinaryWriterExImpl writer(PortableOutputStream out) { + return new BinaryWriterExImpl(ctx, out, BinaryThreadLocalContext.get().schemaHolder(), null); + } + + /** + * @return Context. + */ + public PortableContext context() { + return ctx; + } +}
