http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java index de2b810,0000000..5421bea mode 100644,000000..100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java @@@ -1,1892 -1,0 +1,1855 @@@ +/* + * 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.portable; + +import org.apache.ignite.IgniteCheckedException; ++import org.apache.ignite.igniteobject.IgniteObjectIdMapper; +import org.apache.ignite.internal.portable.streams.PortableHeapOutputStream; +import org.apache.ignite.internal.portable.streams.PortableOutputStream; +import org.apache.ignite.internal.util.typedef.internal.A; +import org.apache.ignite.igniteobject.IgniteObjectException; +import org.apache.ignite.igniteobject.IgniteObjectRawWriter; +import org.apache.ignite.igniteobject.IgniteObjectWriter; +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.IdentityHashMap; +import java.util.Map; +import java.util.UUID; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.CLASS; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.COL; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DECIMAL; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DECIMAL_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.ENUM; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.ENUM_ARR; ++import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLAGS_POS; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.INT; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.INT_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP_ENTRY; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.NULL; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.OPTM_MARSH; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.PORTABLE_OBJ; - import static org.apache.ignite.internal.portable.GridPortableMarshaller.RAW_DATA_OFF_POS; ++import static org.apache.ignite.internal.portable.GridPortableMarshaller.SCHEMA_ID_POS; ++import static org.apache.ignite.internal.portable.GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.STRING; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.STRING_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.TIMESTAMP; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.TIMESTAMP_ARR; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.TOTAL_LEN_POS; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.UNREGISTERED_TYPE_ID; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.UUID; +import static org.apache.ignite.internal.portable.GridPortableMarshaller.UUID_ARR; + - /** ++/** + * Portable writer implementation. + */ +public class IgniteObjectWriterExImpl implements IgniteObjectWriter, IgniteObjectRawWriterEx, ObjectOutput { + /** Length: integer. */ + private static final int LEN_INT = 4; + + /** */ + private static final int INIT_CAP = 1024; + - /** */ - private final PortableContext ctx; ++ /** FNV1 hash offset basis. */ ++ private static final int FNV1_OFFSET_BASIS = 0x811C9DC5; + - /** */ - private final WriterContext wCtx; ++ /** FNV1 hash prime. */ ++ private static final int FNV1_PRIME = 0x01000193; ++ ++ /** Thread-local schema. */ ++ private static final ThreadLocal<SchemaHolder> SCHEMA = new ThreadLocal<>(); + + /** */ - private final int start; ++ private final PortableContext ctx; + + /** */ - private int mark; ++ private final int start; + + /** */ + private Class<?> cls; + + /** */ + private int typeId; + - /** */ - private boolean allowFields = true; ++ /** Raw offset position. */ ++ private int rawOffPos; + + /** */ + private boolean metaEnabled; + + /** */ + private int metaHashSum; + - /** - * @param ctx Context. - * @param off Start offset. - */ - IgniteObjectWriterExImpl(PortableContext ctx, int off) { - this.ctx = ctx; ++ /** Handles. */ ++ private Map<Object, Integer> handles; + - PortableOutputStream out = new PortableHeapOutputStream(off + INIT_CAP); ++ /** Output stream. */ ++ private PortableOutputStream out; + - out.position(off); ++ /** Schema. */ ++ private SchemaHolder schema; + - wCtx = new WriterContext(out, null); ++ /** Schema ID. */ ++ private int schemaId; + - start = off; - } ++ /** Amount of written fields. */ ++ private int fieldCnt; ++ ++ /** ID mapper. */ ++ private IgniteObjectIdMapper idMapper; + + /** + * @param ctx Context. - * @param out Output stream. - * @param off Start offset. + */ - IgniteObjectWriterExImpl(PortableContext ctx, PortableOutputStream out, int off) { - this.ctx = ctx; - - wCtx = new WriterContext(out, null); - - start = off; ++ IgniteObjectWriterExImpl(PortableContext ctx) { ++ this(ctx, new PortableHeapOutputStream(INIT_CAP)); + } + + /** + * @param ctx Context. - * @param off Start offset. - * @param typeId Type ID. ++ * @param out Output stream. + */ - public IgniteObjectWriterExImpl(PortableContext ctx, int off, int typeId, boolean metaEnabled) { - this(ctx, off); ++ IgniteObjectWriterExImpl(PortableContext ctx, PortableOutputStream out) { ++ this(ctx, out, new IdentityHashMap<Object, Integer>()); ++ } + - this.typeId = typeId; ++ /** ++ * @param ctx Context. ++ * @param out Output stream. ++ * @param handles Handles. ++ */ ++ private IgniteObjectWriterExImpl(PortableContext ctx, PortableOutputStream out, Map<Object, Integer> handles) { ++ this.ctx = ctx; ++ this.out = out; ++ this.handles = handles; + - this.metaEnabled = metaEnabled; - } ++ start = out.position(); ++ } + + /** + * @param ctx Context. - * @param wCtx Writer context. ++ * @param typeId Type ID. + */ - private IgniteObjectWriterExImpl(PortableContext ctx, WriterContext wCtx) { - this.ctx = ctx; - this.wCtx = wCtx; ++ public IgniteObjectWriterExImpl(PortableContext ctx, int typeId, boolean metaEnabled) { ++ this(ctx); + - start = wCtx.out.position(); ++ this.typeId = typeId; ++ this.metaEnabled = metaEnabled; + } + + /** + * Close the writer releasing resources if necessary. + */ + @Override public void close() { - wCtx.out.close(); ++ out.close(); + } + + /** + * @return Meta data hash sum or {@code null} if meta data is disabled. + */ + @Nullable Integer metaDataHashSum() { + return metaEnabled ? metaHashSum : null; + } + + /** + * @param obj Object. - * @param detached Detached or not. - * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. ++ * @throws IgniteObjectException In case of error. ++ */ ++ void marshal(Object obj) throws IgniteObjectException { ++ marshal(obj, true); ++ } ++ ++ /** ++ * @param obj Object. ++ * @param enableReplace Object replacing enabled flag. ++ * @throws IgniteObjectException In case of error. + */ - void marshal(Object obj, boolean detached) throws IgniteObjectException { ++ void marshal(Object obj, boolean enableReplace) throws IgniteObjectException { + assert obj != null; + + cls = obj.getClass(); + + PortableClassDescriptor desc = ctx.descriptorForClass(cls); + + if (desc == null) + throw new IgniteObjectException("Object is not portable: [class=" + cls + ']'); + + if (desc.excluded()) { + doWriteByte(NULL); + return; + } + + if (desc.useOptimizedMarshaller()) { + writeByte(OPTM_MARSH); + + try { + byte[] arr = ctx.optimizedMarsh().marshal(obj); + + writeInt(arr.length); + + write(arr); + } + catch (IgniteCheckedException e) { + throw new IgniteObjectException("Failed to marshal object with optimized marshaller: " + obj, e); + } + + return; + } + - if (desc.getWriteReplaceMethod() != null) { - Object replace; ++ if (enableReplace && desc.getWriteReplaceMethod() != null) { ++ Object replacedObj; + + try { - replace = desc.getWriteReplaceMethod().invoke(obj); ++ replacedObj = desc.getWriteReplaceMethod().invoke(obj); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + if (e.getTargetException() instanceof IgniteObjectException) + throw (IgniteObjectException)e.getTargetException(); + + throw new IgniteObjectException("Failed to execute writeReplace() method on " + obj, e); + } + - if (replace == null) { ++ if (replacedObj == null) { + doWriteByte(NULL); + return; + } + - if (cls != replace.getClass()) { - cls = replace.getClass(); - - desc = ctx.descriptorForClass(cls); - - if (desc == null) - throw new IgniteObjectException("Object is not portable: [class=" + cls + ']'); - } ++ marshal(replacedObj, false); + - obj = replace; ++ return; + } + + typeId = desc.typeId(); + + metaEnabled = ctx.isMetaDataEnabled(typeId); + - if (detached) - wCtx.resetHandles(); - + desc.write(obj, this); + } + + /** + * @param obj Object. + * @return Handle. + */ + int handle(Object obj) { + assert obj != null; + - return wCtx.handle(obj); ++ Integer h = handles.get(obj); ++ ++ if (h != null) ++ return out.position() - h; ++ else { ++ handles.put(obj, out.position()); ++ ++ return -1; ++ } + } + + /** + * @return Array. + */ + public byte[] array() { - return wCtx.out.arrayCopy(); - } - - /** - * @return Output stream. - */ - public PortableOutputStream outputStream() { - return wCtx.out; ++ return out.arrayCopy(); + } + + /** + * @return Stream current position. + */ + int position() { - return wCtx.out.position(); ++ return out.position(); + } + + /** + * Sets new position. + * + * @param pos Position. + */ + void position(int pos) { - wCtx.out.position(pos); ++ out.position(pos); + } + - /** ++ /** + * @param bytes Number of bytes to reserve. + * @return Offset. + */ + public int reserve(int bytes) { - int pos = wCtx.out.position(); ++ int pos = out.position(); + - wCtx.out.position(pos + bytes); ++ out.position(pos + bytes); + + return pos; + } + + /** - * @param bytes Number of bytes to reserve. - * @return Offset. ++ * Perform post-write activity. This includes: ++ * - writing object length; ++ * - writing schema offset; ++ * - writing schema to the tail. ++ * ++ * @param userType User type flag. + */ - public int reserveAndMark(int bytes) { - int off0 = reserve(bytes); ++ public void postWrite(boolean userType) { ++ if (schema != null) { ++ // Write schema ID. ++ out.writeInt(start + SCHEMA_ID_POS, schemaId); + - mark = wCtx.out.position(); ++ // Write schema offset. ++ out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - start); + - return off0; - } ++ // Write the schema. ++ schema.writeAndPop(this, fieldCnt); + - /** - * @param off Offset. - */ - public void writeDelta(int off) { - wCtx.out.writeInt(off, wCtx.out.position() - mark); - } ++ // Write raw offset if needed. ++ if (rawOffPos != 0) ++ out.writeInt(rawOffPos - start); ++ } ++ else { ++ // Write raw-only flag is needed. ++ int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_RAW_ONLY; + - /** - * - */ - public void writeLength() { - wCtx.out.writeInt(start + TOTAL_LEN_POS, wCtx.out.position() - start); - } ++ out.writeShort(start + FLAGS_POS, (short)flags); + - /** - * - */ - public void writeRawOffsetIfNeeded() { - if (allowFields) - wCtx.out.writeInt(start + RAW_DATA_OFF_POS, wCtx.out.position() - start); ++ // If there are no schema, we are free to write raw offset to schema offset. ++ out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, (rawOffPos == 0 ? out.position() : rawOffPos) - start); ++ } ++ ++ // 5. Write length. ++ out.writeInt(start + TOTAL_LEN_POS, out.position() - start); + } + + /** + * @param val Byte array. + */ + public void write(byte[] val) { + assert val != null; + - wCtx.out.writeByteArray(val); ++ 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; + - wCtx.out.write(val, off, len); ++ out.write(val, off, len); + } + + /** + * @param val Value. + */ + public void doWriteByte(byte val) { - wCtx.out.writeByte(val); ++ out.writeByte(val); + } + + /** + * @param val Value. + */ + public void doWriteShort(short val) { - wCtx.out.writeShort(val); ++ out.writeShort(val); + } + + /** + * @param val Value. + */ + public void doWriteInt(int val) { - wCtx.out.writeInt(val); ++ out.writeInt(val); + } + + /** + * @param val Value. + */ + public void doWriteLong(long val) { - wCtx.out.writeLong(val); ++ out.writeLong(val); + } + + /** + * @param val Value. + */ + public void doWriteFloat(float val) { - wCtx.out.writeFloat(val); ++ out.writeFloat(val); + } + + /** + * @param val Value. + */ + public void doWriteDouble(double val) { - wCtx.out.writeDouble(val); ++ out.writeDouble(val); + } + + /** + * @param val Value. + */ + public void doWriteChar(char val) { - wCtx.out.writeChar(val); ++ out.writeChar(val); + } + + /** + * @param val Value. + */ + public void doWriteBoolean(boolean val) { - wCtx.out.writeBoolean(val); ++ out.writeBoolean(val); + } + + /** + * @param val String value. + */ + public void doWriteDecimal(@Nullable BigDecimal val) { + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(DECIMAL); + + BigInteger intVal = val.unscaledValue(); + + if (intVal.signum() == -1) { + intVal = intVal.negate(); + - wCtx.out.writeInt(val.scale() | 0x80000000); ++ out.writeInt(val.scale() | 0x80000000); + } + else - wCtx.out.writeInt(val.scale()); ++ out.writeInt(val.scale()); + + byte[] vals = intVal.toByteArray(); + - wCtx.out.writeInt(vals.length); - wCtx.out.writeByteArray(vals); ++ out.writeInt(vals.length); ++ out.writeByteArray(vals); + } + } + + /** + * @param val String value. + */ + public void doWriteString(@Nullable String val) { + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(STRING); + + if (ctx.isConvertString()) { + doWriteBoolean(true); + + byte[] strArr = val.getBytes(UTF_8); + + doWriteInt(strArr.length); + - wCtx.out.writeByteArray(strArr); ++ out.writeByteArray(strArr); + } + else { + doWriteBoolean(false); + + char[] strArr = val.toCharArray(); + + doWriteInt(strArr.length); + - wCtx.out.writeCharArray(strArr); ++ out.writeCharArray(strArr); + } + } + } + + /** + * @param uuid UUID. + */ + public void doWriteUuid(@Nullable UUID uuid) { + if (uuid == null) + doWriteByte(NULL); + else { + doWriteByte(UUID); + doWriteLong(uuid.getMostSignificantBits()); + doWriteLong(uuid.getLeastSignificantBits()); + } + } + + /** + * @param date Date. + */ + public void doWriteDate(@Nullable Date date) { + if (date == null) + doWriteByte(NULL); + else { + doWriteByte(DATE); + doWriteLong(date.getTime()); + } + } + - /** - * @param ts Timestamp. - */ - public void doWriteTimestamp(@Nullable Timestamp ts) { - if (ts== null) - doWriteByte(NULL); - else { - doWriteByte(TIMESTAMP); - doWriteLong(ts.getTime()); - doWriteInt(ts.getNanos() % 1000000); - } - } ++ /** ++ * @param ts Timestamp. ++ */ ++ public void doWriteTimestamp(@Nullable Timestamp ts) { ++ if (ts== null) ++ doWriteByte(NULL); ++ else { ++ doWriteByte(TIMESTAMP); ++ doWriteLong(ts.getTime()); ++ doWriteInt(ts.getNanos() % 1000000); ++ } ++ } + + /** ++ * Write object. ++ * + * @param obj Object. - * @param detached Detached or not. - * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. ++ * @throws IgniteObjectException In case of error. + */ - public void doWriteObject(@Nullable Object obj, boolean detached) throws IgniteObjectException { ++ public void doWriteObject(@Nullable Object obj) throws IgniteObjectException { + if (obj == null) + doWriteByte(NULL); + else { - WriterContext wCtx = detached ? new WriterContext(this.wCtx.out, this.wCtx.handles) : this.wCtx; - - IgniteObjectWriterExImpl writer = new IgniteObjectWriterExImpl(ctx, wCtx); - - writer.marshal(obj, detached); ++ IgniteObjectWriterExImpl writer = new IgniteObjectWriterExImpl(ctx, out, handles); + - if (detached) - this.wCtx.out = wCtx.out; ++ writer.marshal(obj); + } + } + + /** + * @param val Byte array. + */ + void doWriteByteArray(@Nullable byte[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(BYTE_ARR); + doWriteInt(val.length); + - wCtx.out.writeByteArray(val); ++ out.writeByteArray(val); + } + } + + /** + * @param val Short array. + */ + void doWriteShortArray(@Nullable short[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(SHORT_ARR); + doWriteInt(val.length); + - wCtx.out.writeShortArray(val); ++ out.writeShortArray(val); + } + } + + /** + * @param val Integer array. + */ + void doWriteIntArray(@Nullable int[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(INT_ARR); + doWriteInt(val.length); + - wCtx.out.writeIntArray(val); ++ out.writeIntArray(val); + } + } + + /** + * @param val Long array. + */ + void doWriteLongArray(@Nullable long[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(LONG_ARR); + doWriteInt(val.length); + - wCtx.out.writeLongArray(val); ++ out.writeLongArray(val); + } + } + + /** + * @param val Float array. + */ + void doWriteFloatArray(@Nullable float[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(FLOAT_ARR); + doWriteInt(val.length); + - wCtx.out.writeFloatArray(val); ++ out.writeFloatArray(val); + } + } + + /** + * @param val Double array. + */ + void doWriteDoubleArray(@Nullable double[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(DOUBLE_ARR); + doWriteInt(val.length); + - wCtx.out.writeDoubleArray(val); ++ out.writeDoubleArray(val); + } + } + + /** + * @param val Char array. + */ + void doWriteCharArray(@Nullable char[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(CHAR_ARR); + doWriteInt(val.length); + - wCtx.out.writeCharArray(val); ++ out.writeCharArray(val); + } + } + + /** + * @param val Boolean array. + */ + void doWriteBooleanArray(@Nullable boolean[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(BOOLEAN_ARR); + doWriteInt(val.length); + - wCtx.out.writeBooleanArray(val); ++ out.writeBooleanArray(val); + } + } + + /** + * @param val Array of strings. + */ + void doWriteDecimalArray(@Nullable BigDecimal[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(DECIMAL_ARR); + doWriteInt(val.length); + + for (BigDecimal str : val) + doWriteDecimal(str); + } + } + + /** + * @param val Array of strings. + */ + void doWriteStringArray(@Nullable String[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(STRING_ARR); + doWriteInt(val.length); + + for (String str : val) + doWriteString(str); + } + } + + /** + * @param val Array of UUIDs. + */ + void doWriteUuidArray(@Nullable UUID[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(UUID_ARR); + doWriteInt(val.length); + + for (UUID uuid : val) + doWriteUuid(uuid); + } + } + + /** + * @param val Array of dates. + */ + void doWriteDateArray(@Nullable Date[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(DATE_ARR); + doWriteInt(val.length); + + for (Date date : val) + doWriteDate(date); + } + } + + /** + * @param val Array of timestamps. + */ + void doWriteTimestampArray(@Nullable Timestamp[] val) { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + doWriteByte(TIMESTAMP_ARR); + doWriteInt(val.length); + + for (Timestamp ts : val) + doWriteTimestamp(ts); + } + } + + /** + * @param val Array of objects. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void doWriteObjectArray(@Nullable Object[] val) throws IgniteObjectException { + if (val == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(val)) + return; + + PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType()); + + doWriteByte(OBJ_ARR); + + if (desc.registered()) + doWriteInt(desc.typeId()); + else { + doWriteInt(UNREGISTERED_TYPE_ID); + doWriteString(val.getClass().getComponentType().getName()); + } + + doWriteInt(val.length); + + for (Object obj : val) - doWriteObject(obj, false); ++ doWriteObject(obj); + } + } + + /** + * @param col Collection. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void doWriteCollection(@Nullable Collection<?> col) throws IgniteObjectException { + if (col == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(col)) + return; + + doWriteByte(COL); + doWriteInt(col.size()); + doWriteByte(ctx.collectionType(col.getClass())); + + for (Object obj : col) - doWriteObject(obj, false); ++ doWriteObject(obj); + } + } + + /** + * @param map Map. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void doWriteMap(@Nullable Map<?, ?> map) throws IgniteObjectException { + if (map == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(map)) + return; + + doWriteByte(MAP); + doWriteInt(map.size()); + doWriteByte(ctx.mapType(map.getClass())); + + for (Map.Entry<?, ?> e : map.entrySet()) { - doWriteObject(e.getKey(), false); - doWriteObject(e.getValue(), false); ++ doWriteObject(e.getKey()); ++ doWriteObject(e.getValue()); + } + } + } + + /** + * @param e Map entry. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void doWriteMapEntry(@Nullable Map.Entry<?, ?> e) throws IgniteObjectException { + if (e == null) + doWriteByte(NULL); + else { + if (tryWriteAsHandle(e)) + return; + + doWriteByte(MAP_ENTRY); - doWriteObject(e.getKey(), false); - doWriteObject(e.getValue(), false); ++ doWriteObject(e.getKey()); ++ doWriteObject(e.getValue()); + } + } + + /** + * @param val Value. + */ + void doWriteEnum(@Nullable Enum<?> val) { + if (val == null) + doWriteByte(NULL); + else { + PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass()); + + doWriteByte(ENUM); + + if (desc.registered()) + doWriteInt(desc.typeId()); + else { + doWriteInt(UNREGISTERED_TYPE_ID); + doWriteString(val.getClass().getName()); + } + + doWriteInt(val.ordinal()); + } + } + + /** + * @param val Array. + */ + void doWriteEnumArray(@Nullable Object[] val) { + assert val == null || val.getClass().getComponentType().isEnum(); + + if (val == null) + doWriteByte(NULL); + else { + PortableClassDescriptor desc = ctx.descriptorForClass(val.getClass().getComponentType()); + doWriteByte(ENUM_ARR); + + if (desc.registered()) + doWriteInt(desc.typeId()); + else { + doWriteInt(UNREGISTERED_TYPE_ID); + doWriteString(val.getClass().getComponentType().getName()); + } + + doWriteInt(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) + doWriteByte(NULL); + else { + PortableClassDescriptor desc = ctx.descriptorForClass(val); + + doWriteByte(CLASS); + + if (desc.registered()) + doWriteInt(desc.typeId()); + else { + doWriteInt(UNREGISTERED_TYPE_ID); + doWriteString(val.getClass().getName()); + } + } + } + + /** + * @param po Portable object. + */ + public void doWritePortableObject(@Nullable IgniteObjectImpl po) { + if (po == null) + doWriteByte(NULL); + else { + doWriteByte(PORTABLE_OBJ); + + byte[] poArr = po.array(); + + doWriteInt(poArr.length); + - wCtx.out.writeByteArray(poArr); ++ out.writeByteArray(poArr); + + doWriteInt(po.start()); + } + } + + /** + * @param val Value. + */ + void writeByteField(@Nullable Byte val) { - doWriteInt(val != null ? 2 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(BYTE); + doWriteByte(val); + } + } + + /** + * @param val Class. + */ + void writeClassField(@Nullable Class val) { - int lenPos = reserveAndMark(4); - + doWriteClass(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeShortField(@Nullable Short val) { - doWriteInt(val != null ? 3 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(SHORT); + doWriteShort(val); + } + } + + /** + * @param val Value. + */ + void writeIntField(@Nullable Integer val) { - doWriteInt(val != null ? 5 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(INT); + doWriteInt(val); + } + } + + /** + * @param val Value. + */ + void writeLongField(@Nullable Long val) { - doWriteInt(val != null ? 9 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(LONG); + doWriteLong(val); + } + } + + /** + * @param val Value. + */ + void writeFloatField(@Nullable Float val) { - doWriteInt(val != null ? 5 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(FLOAT); + doWriteFloat(val); + } + } + + /** + * @param val Value. + */ + void writeDoubleField(@Nullable Double val) { - doWriteInt(val != null ? 9 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(DOUBLE); + doWriteDouble(val); + } + } + + /** + * @param val Value. + */ + void writeCharField(@Nullable Character val) { - doWriteInt(val != null ? 3 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(CHAR); + doWriteChar(val); + } + } + + /** + * @param val Value. + */ + void writeBooleanField(@Nullable Boolean val) { - doWriteInt(val != null ? 2 : 1); - + if (val == null) + doWriteByte(NULL); + else { + doWriteByte(BOOLEAN); + doWriteBoolean(val); + } + } + + /** + * @param val Value. + */ + void writeDecimalField(@Nullable BigDecimal val) { - int lenPos = reserveAndMark(4); - + doWriteDecimal(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeStringField(@Nullable String val) { - int lenPos = reserveAndMark(4); - + doWriteString(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeUuidField(@Nullable UUID val) { - doWriteInt(val != null ? 17 : 1); + doWriteUuid(val); + } + + /** + * @param val Value. + */ + void writeDateField(@Nullable Date val) { - doWriteInt(val != null ? 9 : 1); + doWriteDate(val); + } + + /** + * @param val Value. + */ + void writeTimestampField(@Nullable Timestamp val) { - doWriteInt(val != null ? 13 : 1); + doWriteTimestamp(val); + } + + /** + * @param obj Object. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void writeObjectField(@Nullable Object obj) throws IgniteObjectException { - int lenPos = reserveAndMark(4); - - doWriteObject(obj, false); - - writeDelta(lenPos); ++ doWriteObject(obj); + } + + /** + * @param val Value. + */ + void writeByteArrayField(@Nullable byte[] val) { - int lenPos = reserveAndMark(4); - + doWriteByteArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeShortArrayField(@Nullable short[] val) { - int lenPos = reserveAndMark(4); - + doWriteShortArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeIntArrayField(@Nullable int[] val) { - int lenPos = reserveAndMark(4); - + doWriteIntArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeLongArrayField(@Nullable long[] val) { - int lenPos = reserveAndMark(4); - + doWriteLongArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeFloatArrayField(@Nullable float[] val) { - int lenPos = reserveAndMark(4); - + doWriteFloatArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeDoubleArrayField(@Nullable double[] val) { - int lenPos = reserveAndMark(4); - + doWriteDoubleArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeCharArrayField(@Nullable char[] val) { - int lenPos = reserveAndMark(4); - + doWriteCharArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeBooleanArrayField(@Nullable boolean[] val) { - int lenPos = reserveAndMark(4); - + doWriteBooleanArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeDecimalArrayField(@Nullable BigDecimal[] val) { - int lenPos = reserveAndMark(4); - + doWriteDecimalArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeStringArrayField(@Nullable String[] val) { - int lenPos = reserveAndMark(4); - + doWriteStringArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeUuidArrayField(@Nullable UUID[] val) { - int lenPos = reserveAndMark(4); - + doWriteUuidArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeDateArrayField(@Nullable Date[] val) { - int lenPos = reserveAndMark(4); - + doWriteDateArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeTimestampArrayField(@Nullable Timestamp[] val) { - int lenPos = reserveAndMark(4); - + doWriteTimestampArray(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void writeObjectArrayField(@Nullable Object[] val) throws IgniteObjectException { - int lenPos = reserveAndMark(4); - + doWriteObjectArray(val); - - writeDelta(lenPos); + } + + /** + * @param col Collection. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void writeCollectionField(@Nullable Collection<?> col) throws IgniteObjectException { - int lenPos = reserveAndMark(4); - + doWriteCollection(col); - - writeDelta(lenPos); + } + + /** + * @param map Map. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void writeMapField(@Nullable Map<?, ?> map) throws IgniteObjectException { - int lenPos = reserveAndMark(4); - + doWriteMap(map); - - writeDelta(lenPos); + } + + /** + * @param e Map entry. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void writeMapEntryField(@Nullable Map.Entry<?, ?> e) throws IgniteObjectException { - int lenPos = reserveAndMark(4); - + doWriteMapEntry(e); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeEnumField(@Nullable Enum<?> val) { - int lenPos = reserveAndMark(4); - + doWriteEnum(val); - - writeDelta(lenPos); + } + + /** + * @param val Value. + */ + void writeEnumArrayField(@Nullable Object[] val) { - int lenPos = reserveAndMark(4); - + doWriteEnumArray(val); - - writeDelta(lenPos); + } + + /** + * @param po Portable object. + * @throws org.apache.ignite.igniteobject.IgniteObjectException In case of error. + */ + void writePortableObjectField(@Nullable IgniteObjectImpl po) throws IgniteObjectException { - int lenPos = reserveAndMark(4); - + doWritePortableObject(po); - - writeDelta(lenPos); + } + + /** {@inheritDoc} */ + @Override public void writeByte(String fieldName, byte val) throws IgniteObjectException { + writeFieldId(fieldName, BYTE); + writeByteField(val); + } + + /** {@inheritDoc} */ + @Override public void writeByte(byte val) throws IgniteObjectException { + doWriteByte(val); + } + + /** {@inheritDoc} */ + @Override public void writeShort(String fieldName, short val) throws IgniteObjectException { + writeFieldId(fieldName, SHORT); + writeShortField(val); + } + + /** {@inheritDoc} */ + @Override public void writeShort(short val) throws IgniteObjectException { + doWriteShort(val); + } + + /** {@inheritDoc} */ + @Override public void writeInt(String fieldName, int val) throws IgniteObjectException { + writeFieldId(fieldName, INT); + writeIntField(val); + } + + /** {@inheritDoc} */ + @Override public void writeInt(int val) throws IgniteObjectException { + doWriteInt(val); + } + + /** {@inheritDoc} */ + @Override public void writeLong(String fieldName, long val) throws IgniteObjectException { + writeFieldId(fieldName, LONG); + writeLongField(val); + } + + /** {@inheritDoc} */ + @Override public void writeLong(long val) throws IgniteObjectException { + doWriteLong(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(String fieldName, float val) throws IgniteObjectException { + writeFieldId(fieldName, FLOAT); + writeFloatField(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloat(float val) throws IgniteObjectException { + doWriteFloat(val); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(String fieldName, double val) throws IgniteObjectException { + writeFieldId(fieldName, DOUBLE); + writeDoubleField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDouble(double val) throws IgniteObjectException { + doWriteDouble(val); + } + + /** {@inheritDoc} */ + @Override public void writeChar(String fieldName, char val) throws IgniteObjectException { + writeFieldId(fieldName, CHAR); + writeCharField(val); + } + + /** {@inheritDoc} */ + @Override public void writeChar(char val) throws IgniteObjectException { + doWriteChar(val); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(String fieldName, boolean val) throws IgniteObjectException { + writeFieldId(fieldName, BOOLEAN); + writeBooleanField(val); + } + + /** {@inheritDoc} */ + @Override public void writeBoolean(boolean val) throws IgniteObjectException { + doWriteBoolean(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws IgniteObjectException { + writeFieldId(fieldName, DECIMAL); + writeDecimalField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimal(@Nullable BigDecimal val) throws IgniteObjectException { + doWriteDecimal(val); + } + + /** {@inheritDoc} */ + @Override public void writeString(String fieldName, @Nullable String val) throws IgniteObjectException { + writeFieldId(fieldName, STRING); + writeStringField(val); + } + + /** {@inheritDoc} */ + @Override public void writeString(@Nullable String val) throws IgniteObjectException { + doWriteString(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuid(String fieldName, @Nullable UUID val) throws IgniteObjectException { + writeFieldId(fieldName, UUID); + writeUuidField(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuid(@Nullable UUID val) throws IgniteObjectException { + doWriteUuid(val); + } + + /** {@inheritDoc} */ + @Override public void writeDate(String fieldName, @Nullable Date val) throws IgniteObjectException { + writeFieldId(fieldName, DATE); + writeDateField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDate(@Nullable Date val) throws IgniteObjectException { + doWriteDate(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws IgniteObjectException { + writeFieldId(fieldName, TIMESTAMP); + writeTimestampField(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestamp(@Nullable Timestamp val) throws IgniteObjectException { + doWriteTimestamp(val); + } + + /** {@inheritDoc} */ + @Override public void writeObject(String fieldName, @Nullable Object obj) throws IgniteObjectException { + writeFieldId(fieldName, OBJ); + writeObjectField(obj); + } + + /** {@inheritDoc} */ + @Override public void writeObject(@Nullable Object obj) throws IgniteObjectException { - doWriteObject(obj, false); ++ doWriteObject(obj); + } + + /** {@inheritDoc} */ + @Override public void writeObjectDetached(@Nullable Object obj) throws IgniteObjectException { - doWriteObject(obj, true); ++ if (obj == null) ++ doWriteByte(NULL); ++ else { ++ IgniteObjectWriterExImpl writer = new IgniteObjectWriterExImpl(ctx, out, new IdentityHashMap<Object, Integer>()); ++ ++ writer.marshal(obj); ++ } + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws IgniteObjectException { + writeFieldId(fieldName, BYTE_ARR); + writeByteArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeByteArray(@Nullable byte[] val) throws IgniteObjectException { + doWriteByteArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws IgniteObjectException { + writeFieldId(fieldName, SHORT_ARR); + writeShortArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeShortArray(@Nullable short[] val) throws IgniteObjectException { + doWriteShortArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws IgniteObjectException { + writeFieldId(fieldName, INT_ARR); + writeIntArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeIntArray(@Nullable int[] val) throws IgniteObjectException { + doWriteIntArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws IgniteObjectException { + writeFieldId(fieldName, LONG_ARR); + writeLongArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeLongArray(@Nullable long[] val) throws IgniteObjectException { + doWriteLongArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws IgniteObjectException { + writeFieldId(fieldName, FLOAT_ARR); + writeFloatArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeFloatArray(@Nullable float[] val) throws IgniteObjectException { + doWriteFloatArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(String fieldName, @Nullable double[] val) + throws IgniteObjectException { + writeFieldId(fieldName, DOUBLE_ARR); + writeDoubleArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDoubleArray(@Nullable double[] val) throws IgniteObjectException { + doWriteDoubleArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws IgniteObjectException { + writeFieldId(fieldName, CHAR_ARR); + writeCharArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeCharArray(@Nullable char[] val) throws IgniteObjectException { + doWriteCharArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val) + throws IgniteObjectException { + writeFieldId(fieldName, BOOLEAN_ARR); + writeBooleanArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeBooleanArray(@Nullable boolean[] val) throws IgniteObjectException { + doWriteBooleanArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val) + throws IgniteObjectException { + writeFieldId(fieldName, DECIMAL_ARR); + writeDecimalArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDecimalArray(@Nullable BigDecimal[] val) throws IgniteObjectException { + doWriteDecimalArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(String fieldName, @Nullable String[] val) + throws IgniteObjectException { + writeFieldId(fieldName, STRING_ARR); + writeStringArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeStringArray(@Nullable String[] val) throws IgniteObjectException { + doWriteStringArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws IgniteObjectException { + writeFieldId(fieldName, UUID_ARR); + writeUuidArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeUuidArray(@Nullable UUID[] val) throws IgniteObjectException { + doWriteUuidArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws IgniteObjectException { + writeFieldId(fieldName, DATE_ARR); + writeDateArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeDateArray(@Nullable Date[] val) throws IgniteObjectException { + doWriteDateArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws IgniteObjectException { + writeFieldId(fieldName, TIMESTAMP_ARR); + writeTimestampArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeTimestampArray(@Nullable Timestamp[] val) throws IgniteObjectException { + doWriteTimestampArray(val); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws IgniteObjectException { + writeFieldId(fieldName, OBJ_ARR); + writeObjectArrayField(val); + } + + /** {@inheritDoc} */ + @Override public void writeObjectArray(@Nullable Object[] val) throws IgniteObjectException { + doWriteObjectArray(val); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col) + throws IgniteObjectException { + writeFieldId(fieldName, COL); + writeCollectionField(col); + } + + /** {@inheritDoc} */ + @Override public <T> void writeCollection(@Nullable Collection<T> col) throws IgniteObjectException { + doWriteCollection(col); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map) + throws IgniteObjectException { + writeFieldId(fieldName, MAP); + writeMapField(map); + } + + /** {@inheritDoc} */ + @Override public <K, V> void writeMap(@Nullable Map<K, V> map) throws IgniteObjectException { + doWriteMap(map); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws IgniteObjectException { + writeFieldId(fieldName, ENUM); + writeEnumField(val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnum(T val) throws IgniteObjectException { + doWriteEnum(val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws IgniteObjectException { + writeFieldId(fieldName, ENUM_ARR); + writeEnumArrayField(val); + } + + /** {@inheritDoc} */ + @Override public <T extends Enum<?>> void writeEnumArray(T[] val) throws IgniteObjectException { + doWriteEnumArray(val); + } + + /** {@inheritDoc} */ + @Override public IgniteObjectRawWriter rawWriter() { - if (allowFields) { - wCtx.out.writeInt(start + RAW_DATA_OFF_POS, wCtx.out.position() - start); - - allowFields = false; - } ++ if (rawOffPos == 0) ++ rawOffPos = out.position(); + + return this; + } + + /** {@inheritDoc} */ + @Override public PortableOutputStream out() { - return wCtx.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 { - doWriteByte((byte)v); ++ doWriteByte((byte) v); + } + + /** {@inheritDoc} */ + @Override public void writeShort(int v) throws IOException { - doWriteShort((short)v); ++ doWriteShort((short) v); + } + + /** {@inheritDoc} */ + @Override public void writeChar(int v) throws IOException { - doWriteChar((char)v); ++ doWriteChar((char) v); + } + + /** {@inheritDoc} */ + @Override public void write(int b) throws IOException { - doWriteByte((byte)b); ++ doWriteByte((byte) b); + } + + /** {@inheritDoc} */ + @Override public void flush() throws IOException { + // No-op. + } + + /** {@inheritDoc} */ + @Override public int reserveInt() { + return reserve(LEN_INT); + } + - /** {@inheritDoc} */ ++ /** {@inheritDoc} */ + @Override public void writeInt(int pos, int val) throws IgniteObjectException { - wCtx.out.writeInt(pos, val); ++ out.writeInt(pos, val); + } + + /** + * @param fieldName Field name. + * @throws org.apache.ignite.igniteobject.IgniteObjectException If fields are not allowed. + */ + private void writeFieldId(String fieldName, byte fieldType) throws IgniteObjectException { + A.notNull(fieldName, "fieldName"); + - if (!allowFields) ++ if (rawOffPos != 0) + throw new IgniteObjectException("Individual field can't be written after raw writer is acquired " + + "via rawWriter() method. Consider fixing serialization logic for class: " + cls.getName()); + - int id = ctx.fieldId(typeId, fieldName); ++ if (idMapper == null) ++ idMapper = ctx.userTypeIdMapper(typeId); ++ ++ int id = idMapper.fieldId(typeId, fieldName); ++ ++ writeFieldId(id); + + if (metaEnabled) + metaHashSum = 31 * metaHashSum + (id + fieldType); ++ } ++ ++ /** ++ * Write field ID. ++ * @param fieldId Field ID. ++ */ ++ public void writeFieldId(int fieldId) { ++ int fieldOff = out.position() - start; + - doWriteInt(id); ++ if (schema == null) { ++ schema = SCHEMA.get(); ++ ++ if (schema == null) { ++ schema = new SchemaHolder(); ++ ++ SCHEMA.set(schema); ++ } ++ ++ // Initialize offset when the first field is written. ++ schemaId = FNV1_OFFSET_BASIS; ++ } ++ ++ // Advance schema hash. ++ int schemaId0 = schemaId ^ (fieldId & 0xFF); ++ schemaId0 = schemaId0 * FNV1_PRIME; ++ schemaId0 = schemaId0 ^ ((fieldId >> 8) & 0xFF); ++ schemaId0 = schemaId0 * FNV1_PRIME; ++ schemaId0 = schemaId0 ^ ((fieldId >> 16) & 0xFF); ++ schemaId0 = schemaId0 * FNV1_PRIME; ++ schemaId0 = schemaId0 ^ ((fieldId >> 24) & 0xFF); ++ schemaId0 = schemaId0 * FNV1_PRIME; ++ ++ schemaId = schemaId0; ++ ++ schema.push(fieldId, fieldOff); ++ ++ fieldCnt++; + } + - /** - * 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) { - int handle = handle(obj); ++ /** ++ * 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) { ++ int handle = handle(obj); + - if (handle >= 0) { - doWriteByte(GridPortableMarshaller.HANDLE); - doWriteInt(handle); ++ if (handle >= 0) { ++ doWriteByte(GridPortableMarshaller.HANDLE); ++ doWriteInt(handle); + - return true; - } ++ return true; ++ } + - return false; - } ++ return false; ++ } + + /** + * Create new writer with same context. ++ * + * @param typeId type + * @return New writer. + */ + public IgniteObjectWriterExImpl newWriter(int typeId) { - IgniteObjectWriterExImpl res = new IgniteObjectWriterExImpl(ctx, wCtx); ++ IgniteObjectWriterExImpl res = new IgniteObjectWriterExImpl(ctx, out, handles); + + res.typeId = typeId; + + return res; + } + + /** + * @return Portable context. + */ + public PortableContext context() { + return ctx; + } + - /** */ - private static class WriterContext { - /** */ - private Map<Object, Integer> handles = new IdentityHashMap<>(); ++ /** ++ * Schema holder. ++ */ ++ private static class SchemaHolder { ++ /** Grow step. */ ++ private static final int GROW_STEP = 16; ++ ++ /** Maximum stable size. */ ++ private static final int MAX_SIZE = 256; ++ ++ /** Data. */ ++ private int[] data; + - /** Output stream. */ - private PortableOutputStream out; ++ /** Index. */ ++ private int idx; + + /** + * Constructor. - * - * @param out Output stream. - * @param handles Handles. + */ - private WriterContext(PortableOutputStream out, Map<Object, Integer> handles) { - this.out = out; - this.handles = handles == null ? new IdentityHashMap<Object, Integer>() : handles; ++ public SchemaHolder() { ++ data = new int[GROW_STEP]; + } + + /** - * @param obj Object. - * @return Handle. ++ * Push another frame. ++ * ++ * @param id Field ID. ++ * @param off Field offset. + */ - private int handle(Object obj) { - assert obj != null; - - Integer h = handles.get(obj); ++ public void push(int id, int off) { ++ if (idx == data.length) { ++ int[] data0 = new int[data.length + GROW_STEP]; + - if (h != null) - return out.position() - h; - else { - handles.put(obj, out.position()); ++ System.arraycopy(data, 0, data0, 0, data.length); + - return -1; ++ data = data0; + } ++ ++ data[idx] = id; ++ data[idx + 1] = off; ++ ++ idx += 2; + } + + /** ++ * Write collected frames and pop them. + * ++ * @param writer Writer. ++ * @param cnt Count. + */ - private void resetHandles() { - handles = new IdentityHashMap<>(); ++ public void writeAndPop(PortableWriterExImpl writer, int cnt) { ++ int startIdx = idx - cnt * 2; ++ ++ assert startIdx >= 0; ++ ++ for (int idx0 = startIdx; idx0 < idx;) { ++ writer.writeInt(data[idx0++]); ++ writer.writeInt(data[idx0++]); ++ } ++ ++ idx = startIdx; ++ ++ // Shrink data array if needed. ++ if (idx == 0 && data.length > MAX_SIZE) ++ data = new int[MAX_SIZE]; + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java index 2470837,9f7f0c6..4cad80b --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java @@@ -17,6 -17,18 +17,14 @@@ package org.apache.ignite.internal.portable; + import org.apache.ignite.IgniteCheckedException; + import org.apache.ignite.internal.processors.cache.CacheObjectImpl; + import org.apache.ignite.internal.util.typedef.internal.U; + import org.apache.ignite.marshaller.MarshallerExclusions; + import org.apache.ignite.marshaller.optimized.OptimizedMarshaller; + import org.apache.ignite.marshaller.portable.PortableMarshaller; -import org.apache.ignite.portable.PortableException; -import org.apache.ignite.portable.PortableIdMapper; -import org.apache.ignite.portable.PortableMarshalAware; -import org.apache.ignite.portable.PortableSerializer; + import org.jetbrains.annotations.Nullable; + import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInputStream; @@@ -61,8 -62,11 +69,11 @@@ public class PortableClassDescriptor private final Class<?> cls; /** */ - private final PortableSerializer serializer; + private final IgniteObjectSerializer serializer; + /** ID mapper. */ + private final PortableIdMapper idMapper; + /** */ private final Mode mode; @@@ -513,14 -527,13 +534,13 @@@ if (serializer != null) serializer.writePortable(obj, writer); else - ((PortableMarshalAware)obj).writePortable(writer); + ((IgniteObjectMarshalAware)obj).writePortable(writer); - writer.writeRawOffsetIfNeeded(); - writer.writeLength(); + writer.postWrite(userType); - if (obj.getClass() != PortableMetaDataImpl.class + if (obj.getClass() != IgniteObjectMetaDataImpl.class && ctx.isMetaDataChanged(typeId, writer.metaDataHashSum())) { - PortableMetaDataCollector metaCollector = new PortableMetaDataCollector(typeName); + IgniteObjectMetaDataCollector metaCollector = new IgniteObjectMetaDataCollector(typeName); if (serializer != null) serializer.writePortable(obj, metaCollector); @@@ -539,10 -554,10 +561,10 @@@ ((Externalizable)obj).writeExternal(writer); } catch (IOException e) { - throw new PortableException("Failed to write Externalizable object: " + obj, e); + throw new IgniteObjectException("Failed to write Externalizable object: " + obj, e); } - writer.writeLength(); + writer.postWrite(userType); } break; http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java index 471781c,e61cba7..3b32e67 --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java @@@ -81,10 -80,13 +103,13 @@@ public class PortableContext implement private static final long serialVersionUID = 0L; /** */ + private static final ClassLoader dfltLdr = U.gridClassLoader(); + + /** */ - static final PortableIdMapper DFLT_ID_MAPPER = new IdMapperWrapper(null); + static final IgniteObjectIdMapper DFLT_ID_MAPPER = new IdMapperWrapper(null); /** */ - static final PortableIdMapper BASIC_CLS_ID_MAPPER = new BasicClassIdMapper(); + static final IgniteObjectIdMapper BASIC_CLS_ID_MAPPER = new BasicClassIdMapper(); /** */ static final char[] LOWER_CASE_CHARS; @@@ -124,10 -126,10 +149,10 @@@ private final Map<Class<? extends Map>, Byte> mapTypes = new HashMap<>(); /** */ - private final Map<Integer, IgniteObjectIdMapper> mappers = new ConcurrentHashMap8<>(0); - private final ConcurrentMap<Integer, PortableIdMapper> mappers = new ConcurrentHashMap8<>(0); ++ private final ConcurrentMap<Integer, IgniteObjectIdMapper> mappers = new ConcurrentHashMap8<>(0); /** */ - private final Map<String, PortableIdMapper> typeMappers = new ConcurrentHashMap8<>(0); + private final Map<String, IgniteObjectIdMapper> typeMappers = new ConcurrentHashMap8<>(0); /** */ private Map<Integer, Boolean> metaEnabled = new HashMap<>(0); @@@ -475,10 -471,18 +505,18 @@@ desc = descByCls.get(cls); } catch (ClassNotFoundException e) { + // Class might have been loaded by default class loader. + if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr)) != null) + return desc; + - throw new PortableInvalidClassException(e); + throw new IgniteObjectInvalidClassException(e); } catch (IgniteCheckedException e) { + // Class might have been loaded by default class loader. + if (userType && !ldr.equals(dfltLdr) && (desc = descriptorForTypeId(true, typeId, dfltLdr)) != null) + return desc; + - throw new PortableException("Failed resolve class for ID: " + typeId, e); + throw new IgniteObjectException("Failed resolve class for ID: " + typeId, e); } if (desc == null) { @@@ -537,7 -541,7 +575,7 @@@ String typeName = typeName(cls.getName()); - IgniteObjectIdMapper idMapper = idMapper(typeName); - PortableIdMapper idMapper = userTypeIdMapper(typeName); ++ IgniteObjectIdMapper idMapper = userTypeIdMapper(typeName); int typeId = idMapper.typeId(typeName); @@@ -630,8 -639,8 +673,8 @@@ * @param typeId Type ID. * @return Instance of ID mapper. */ - public IgniteObjectIdMapper idMapper(int typeId) { - public PortableIdMapper userTypeIdMapper(int typeId) { - PortableIdMapper idMapper = mappers.get(typeId); ++ public IgniteObjectIdMapper userTypeIdMapper(int typeId) { + IgniteObjectIdMapper idMapper = mappers.get(typeId); if (idMapper != null) return idMapper; @@@ -646,8 -655,8 +689,8 @@@ * @param typeName Type name. * @return Instance of ID mapper. */ - private IgniteObjectIdMapper idMapper(String typeName) { - private PortableIdMapper userTypeIdMapper(String typeName) { - PortableIdMapper idMapper = typeMappers.get(typeName); ++ private IgniteObjectIdMapper userTypeIdMapper(String typeName) { + IgniteObjectIdMapper idMapper = typeMappers.get(typeName); return idMapper != null ? idMapper : DFLT_ID_MAPPER; } @@@ -907,10 -966,26 +1000,26 @@@ } /** + * Undeployment callback invoked when class loader is being undeployed. + * + * Some marshallers may want to clean their internal state that uses the undeployed class loader somehow. + * + * @param ldr Class loader being undeployed. + */ + public void onUndeploy(ClassLoader ldr) { + for (Class<?> cls : descByCls.keySet()) { + if (ldr.equals(cls.getClassLoader())) + descByCls.remove(cls); + } + + U.clearClassCache(ldr); + } + + /** */ - private static class IdMapperWrapper implements PortableIdMapper { + private static class IdMapperWrapper implements IgniteObjectIdMapper { /** */ - private final PortableIdMapper mapper; + private final IgniteObjectIdMapper mapper; /** * @param mapper Custom ID mapper. http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java index bf1c3b6,51fc407..cfe7efe --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java @@@ -20,18 -20,19 +20,19 @@@ package org.apache.ignite.internal.port import java.util.HashMap; import java.util.Map; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.igniteobject.IgniteObject; + import org.apache.ignite.lang.IgniteBiTuple; -import org.apache.ignite.portable.PortableObject; import org.jetbrains.annotations.Nullable; /** - * Reader context. - */ + * Reader context. + */ class PortableReaderContext { /** */ - private Map<Integer, Object> oHandles; + private Object oHandles; /** */ - private Map<Integer, PortableObject> poHandles; + private Map<Integer, IgniteObject> poHandles; /** * @param handle Handle. http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java ---------------------------------------------------------------------- diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java index d6b526d,eafcbd1..e0e6d21 --- a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java @@@ -18,9 -18,11 +18,11 @@@ package org.apache.ignite.internal.portable; import org.apache.ignite.internal.portable.builder.PortableLazyValue; + import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; + import org.apache.ignite.lang.IgniteBiTuple; -import org.apache.ignite.portable.PortableException; -import org.apache.ignite.portable.PortableObject; +import org.apache.ignite.igniteobject.IgniteObjectException; +import org.apache.ignite.igniteobject.IgniteObject; import org.jetbrains.annotations.Nullable; import org.jsr166.ConcurrentHashMap8; @@@ -92,6 -94,47 +94,47 @@@ public class PortableUtils /** Portable classes. */ private static final Collection<Class<?>> PORTABLE_CLS = new HashSet<>(); + /** Flag: user type. */ + public static final short FLAG_USR_TYP = 0x1; + + /** Flag: only raw data exists. */ + public static final short FLAG_RAW_ONLY = 0x2; + + /** + * Write flags. + * + * @param writer Writer. + * @param userType User type flag. + */ - public static void writeFlags(PortableWriterExImpl writer, boolean userType) { ++ public static void writeFlags(IgniteObjectWriterExImpl writer, boolean userType) { + short val = 0; + + if (userType) + val |= FLAG_USR_TYP; + + writer.doWriteShort(val); + } + + /** + * Check if user type flag is set. + * + * @param flags Flags. + * @return {@code True} if set. + */ + public static boolean isUserType(short flags) { + return (flags & FLAG_USR_TYP) == FLAG_USR_TYP; + } + + /** + * Check if raw-only flag is set. + * + * @param flags Flags. + * @return {@code True} if set. + */ + public static boolean isRawOnly(short flags) { + return (flags & FLAG_RAW_ONLY) == FLAG_RAW_ONLY; + } + /** * */ @@@ -485,6 -528,120 +528,120 @@@ */ public static void checkProtocolVersion(byte protoVer) { if (PROTO_VER != protoVer) - throw new PortableException("Unsupported protocol version: " + protoVer); + throw new IgniteObjectException("Unsupported protocol version: " + protoVer); } + + /** + * Write portable header. + * + * @param writer Writer. + * @param usrTyp User type flag. + * @param typeId Type ID. + * @param hashCode Hash code. + * @param clsName Class name (optional). + * @return Position where length should be written. + */ - public static int writeHeader(PortableWriterExImpl writer, boolean usrTyp, int typeId, int hashCode, ++ public static int writeHeader(IgniteObjectWriterExImpl writer, boolean usrTyp, int typeId, int hashCode, + @Nullable String clsName) { + writer.doWriteByte(GridPortableMarshaller.OBJ); + writer.doWriteByte(GridPortableMarshaller.PROTO_VER); + + PortableUtils.writeFlags(writer, usrTyp); + + writer.doWriteInt(typeId); + writer.doWriteInt(hashCode); + + int reserved = writer.reserve(12); + + if (clsName != null) + writer.doWriteString(clsName); + + return reserved; + } + + /** + * Get portable object length. + * + * @param in Input stream. + * @param start Start position. + * @return Length. + */ + public static int length(PortablePositionReadable in, int start) { + return in.readIntPositioned(start + GridPortableMarshaller.TOTAL_LEN_POS); + } + + /** + * Get footer start of the object. + * + * @param in Input stream. + * @param start Object start position inside the stream. + * @return Footer start. + */ + public static int footerStartRelative(PortablePositionReadable in, int start) { + short flags = in.readShortPositioned(start + GridPortableMarshaller.FLAGS_POS); + + if (PortableUtils.isRawOnly(flags)) + // No schema, footer start equals to object end. + return length(in, start); + else + // Schema exists, use offset. + return in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS); + } + + /** + * Get object's footer. + * + * @param in Input stream. + * @param start Start position. + * @return Footer start. + */ + public static int footerStartAbsolute(PortablePositionReadable in, int start) { + return footerStartRelative(in, start) + start; + } + + /** + * Get object's footer. + * + * @param in Input stream. + * @param start Start position. + * @return Footer. + */ + public static IgniteBiTuple<Integer, Integer> footerAbsolute(PortablePositionReadable in, int start) { + int footerStart = footerStartRelative(in, start); + int footerEnd = length(in, start); + + // Take in count possible raw offset. + if ((((footerEnd - footerStart) >> 2) & 0x1) == 0x1) + footerEnd -= 4; + + return F.t(start + footerStart, start + footerEnd); + } + + /** + * Get raw offset of the object. + * + * @param in Input stream. + * @param start Object start position inside the stream. + * @return Raw offset. + */ + public static int rawOffsetAbsolute(PortablePositionReadable in, int start) { + int len = length(in, start); + + short flags = in.readShortPositioned(start + GridPortableMarshaller.FLAGS_POS); + + if (PortableUtils.isRawOnly(flags)) + // No schema, raw offset is located on schema offset position. + return start + in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS); + else { + // Schema exists. + int schemaOff = in.readIntPositioned(start + GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS); + + if ((((len - schemaOff) >> 2) & 0x1) == 0x0) + // Even amount of records in schema => no raw offset. + return start + schemaOff; + else + // Odd amount of records in schema => raw offset is the very last 4 bytes in object. + return start + in.readIntPositioned(start + len - 4); + } + } }
