ignite-950: moved all footer related logic to dedicated class, unmarshalling enclosed objects, wrapping serializable fields with CacheObjectImpl
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/9e2943db Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/9e2943db Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/9e2943db Branch: refs/heads/ignite-950 Commit: 9e2943db84989606ce2b6e19cf0949b77f48be84 Parents: 549a1a7 Author: Denis Magda <[email protected]> Authored: Tue Jun 16 16:44:55 2015 +0300 Committer: Denis Magda <[email protected]> Committed: Tue Jun 16 16:44:55 2015 +0300 ---------------------------------------------------------------------- .../processors/cache/CacheObjectImpl.java | 21 ++ .../cacheobject/IgniteCacheObjectProcessor.java | 4 +- .../IgniteCacheObjectProcessorImpl.java | 15 +- .../ignite/internal/util/io/GridDataInput.java | 7 + .../internal/util/io/GridUnsafeDataInput.java | 5 + .../optimized/OptimizedClassDescriptor.java | 121 ++++---- .../optimized/OptimizedFieldType.java | 2 +- .../optimized/OptimizedMarshaller.java | 77 +---- .../optimized/OptimizedMarshallerUtils.java | 34 +-- .../optimized/OptimizedObjectInputStream.java | 217 +++----------- .../optimized/OptimizedObjectMetadata.java | 149 ---------- .../OptimizedObjectMetadataHandler.java | 40 --- .../optimized/OptimizedObjectMetadataKey.java | 70 ----- .../optimized/OptimizedObjectOutputStream.java | 160 +++++----- .../optimized/ext/OptimizedMarshallerExt.java | 291 +++++++++++++++++++ .../ext/OptimizedMarshallerExtMetaHandler.java | 40 +++ .../ext/OptimizedObjectInputStreamExt.java | 212 ++++++++++++++ .../optimized/ext/OptimizedObjectMetadata.java | 149 ++++++++++ .../ext/OptimizedObjectMetadataKey.java | 70 +++++ .../ext/OptimizedObjectOutputStreamExt.java | 135 +++++++++ .../ext/OptimizedObjectStreamExtRegistry.java | 226 ++++++++++++++ .../marshaller/optimized/ext/package-info.java | 21 ++ .../optimized/OptimizedMarshallerSelfTest.java | 13 - .../OptimizedObjectStreamSelfTest.java | 16 +- .../ext/OptimizedMarshallerExtSelfTest.java | 179 ++++++++++++ .../marshaller/optimized/ext/package-info.java | 22 ++ 26 files changed, 1579 insertions(+), 717 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java index ad033a7..49c0262 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java @@ -104,6 +104,27 @@ public class CacheObjectImpl extends CacheObjectAdapter { val = ctx.processor().unmarshal(ctx, valBytes, ldr); } + /** + * Gets field value. + * + * @param fieldName Field name. + * @return Field value. + * @throws IgniteCheckedException In case of any other error. + */ + @Nullable public <F> F field(String fieldName) throws IgniteCheckedException { + return null; + } + + /** + * Checks whether field is set. + * + * @param fieldName Field name. + * @return {@code true} if field is set. + */ + public boolean hasField(String fieldName) { + return false; + } + /** {@inheritDoc} */ @Override public byte directType() { return 89; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java index c339037..6a5f947 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessor.java @@ -101,11 +101,11 @@ public interface IgniteCacheObjectProcessor extends GridProcessor { * Footer contains information on fields location in the serialized form, thus enabling fast queries without a need * to deserialize the object. * - * @param obj Object. + * @param cls Class. * @return {@code true} if the footer is supported. * @throws IgniteCheckedException If failed. */ - public boolean footerSupported(Object obj) throws IgniteCheckedException; + public boolean footerSupported(Class<?> cls) throws IgniteCheckedException; /** * @param ctx Cache object context. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java index a002d36..7a89598 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cacheobject/IgniteCacheObjectProcessorImpl.java @@ -29,6 +29,7 @@ import org.apache.ignite.internal.util.typedef.internal.*; import org.apache.ignite.lang.*; import org.apache.ignite.marshaller.*; import org.apache.ignite.marshaller.optimized.*; +import org.apache.ignite.marshaller.optimized.ext.*; import org.jetbrains.annotations.*; import java.math.*; @@ -60,7 +61,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme private final CountDownLatch startLatch = new CountDownLatch(1); /** */ - private OptimizedMarshaller optMarsh; + private OptimizedMarshallerExt optMarshExt; /** * @@ -86,10 +87,10 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme Marshaller marsh = ctx.config().getMarshaller(); - if (marsh instanceof OptimizedMarshaller) { - optMarsh = (OptimizedMarshaller)marsh; + if (marsh instanceof OptimizedMarshallerExt) { + optMarshExt = (OptimizedMarshallerExt)marsh; - OptimizedObjectMetadataHandler metaHandler = new OptimizedObjectMetadataHandler() { + OptimizedMarshallerExtMetaHandler metaHandler = new OptimizedMarshallerExtMetaHandler() { @Override public void addMeta(int typeId, OptimizedObjectMetadata meta) { if (metaBuf.contains(typeId)) return; @@ -118,7 +119,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme } }; - optMarsh.setMetadataHandler(metaHandler); + optMarshExt.setMetadataHandler(metaHandler); } } @@ -319,8 +320,8 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme } /** {@inheritDoc} */ - @Override public boolean footerSupported(Object obj) throws IgniteCheckedException { - return optMarsh != null && optMarsh.footerSupported(obj); + @Override public boolean footerSupported(Class<?> cls) throws IgniteCheckedException { + return optMarshExt != null && optMarshExt.metaSupported(cls); } /** http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridDataInput.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridDataInput.java b/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridDataInput.java index 2583673..ad139a2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridDataInput.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridDataInput.java @@ -67,6 +67,13 @@ public interface GridDataInput extends DataInput { public int size() throws IOException; /** + * Returns byte array that is backed by this GridDataInput. + * + * @return Byte array. + */ + public byte[] array(); + + /** * Resets data output. * * @throws IOException In case of error. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridUnsafeDataInput.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridUnsafeDataInput.java b/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridUnsafeDataInput.java index d2ae22d..6be90c5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridUnsafeDataInput.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/io/GridUnsafeDataInput.java @@ -189,6 +189,11 @@ public class GridUnsafeDataInput extends InputStream implements GridDataInput { return off; } + /** {@inheritDoc} */ + @Override public byte[] array() { + return buf; + } + /** * @param more Bytes to move forward. * @return Old offset value. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java index 0ef39b1..ae3ae77 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java @@ -34,7 +34,7 @@ import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.EN /** * Class descriptor. */ -class OptimizedClassDescriptor { +public class OptimizedClassDescriptor { /** Unsafe. */ private static final Unsafe UNSAFE = GridUnsafe.unsafe(); @@ -107,9 +107,6 @@ class OptimizedClassDescriptor { /** Access order field offset. */ private long accessOrderFieldOff; - /** Metadata handler */ - private OptimizedObjectMetadataHandler metaHandler; - /** * Creates descriptor for class. * @@ -118,9 +115,6 @@ class OptimizedClassDescriptor { * @param cls Class. * @param ctx Context. * @param mapper ID mapper. - * @param metaHandler Metadata handler. - * @param tryEnableMeta Try to enable meta during {@code OptimizedClassDescriptor} registration. Meta is supported, - * only for objects that support footer injection is their serialized form. * @throws IOException In case of error. */ @SuppressWarnings("ForLoopReplaceableByForEach") @@ -128,16 +122,13 @@ class OptimizedClassDescriptor { int typeId, ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, MarshallerContext ctx, - OptimizedMarshallerIdMapper mapper, - OptimizedObjectMetadataHandler metaHandler, - boolean tryEnableMeta) + OptimizedMarshallerIdMapper mapper) throws IOException { this.cls = cls; this.typeId = typeId; this.clsMap = clsMap; this.ctx = ctx; this.mapper = mapper; - this.metaHandler = metaHandler; name = cls.getName(); @@ -349,7 +340,7 @@ class OptimizedClassDescriptor { List<ClassFields> fields = new ArrayList<>(); Set<String> fieldsSet = new HashSet<>(); - boolean fieldsIndexingEnabled = true; + boolean fieldsIndexingSupported = true; for (c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { Method mtd; @@ -361,7 +352,7 @@ class OptimizedClassDescriptor { if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE) { mtd.setAccessible(true); - fieldsIndexingEnabled = false; + fieldsIndexingSupported = false; } else // Set method back to null if it has incorrect signature. @@ -380,7 +371,7 @@ class OptimizedClassDescriptor { if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE) { mtd.setAccessible(true); - fieldsIndexingEnabled = false; + fieldsIndexingSupported = false; } else // Set method back to null if it has incorrect signature. @@ -401,7 +392,7 @@ class OptimizedClassDescriptor { // Check for fields duplicate names in classes hierarchy if (!fieldsSet.add(f.getName())) - fieldsIndexingEnabled = false; + fieldsIndexingSupported = false; } List<FieldInfo> clsFields = new ArrayList<>(clsFields0.length); @@ -417,7 +408,7 @@ class OptimizedClassDescriptor { isPrivate(mod) && isStatic(mod) && isFinal(mod)) { hasSerialPersistentFields = true; - fieldsIndexingEnabled = false; + fieldsIndexingSupported = false; serFieldsDesc.setAccessible(true); @@ -488,21 +479,7 @@ class OptimizedClassDescriptor { Collections.reverse(readObjMtds); Collections.reverse(fields); - this.fields = new Fields(fields, fieldsIndexingEnabled); - - if (tryEnableMeta && fieldsIndexingEnabled && metaHandler.metadata(typeId) == null) { - OptimizedObjectMetadata meta = new OptimizedObjectMetadata(); - - for (ClassFields clsFields : this.fields.fields) - for (FieldInfo info : clsFields.fields) - meta.addMeta(info.id(), info.type()); - - U.debug("putting to cache: " + typeId); - - metaHandler.addMeta(typeId, meta); - - U.debug("put to cache: " + typeId); - } + this.fields = new Fields(fields, fieldsIndexingSupported); } } } @@ -659,8 +636,9 @@ class OptimizedClassDescriptor { case OBJ_ARR: OptimizedClassDescriptor compDesc = classDescriptor(clsMap, - obj.getClass().getComponentType(), ctx, - mapper, metaHandler, false); + obj.getClass().getComponentType(), + ctx, + mapper); compDesc.writeTypeData(out); @@ -719,8 +697,7 @@ class OptimizedClassDescriptor { break; case CLS: - OptimizedClassDescriptor clsDesc = classDescriptor(clsMap, (Class<?>)obj, ctx, mapper, metaHandler, - false); + OptimizedClassDescriptor clsDesc = classDescriptor(clsMap, (Class<?>)obj, ctx, mapper); clsDesc.writeTypeData(out); @@ -827,6 +804,15 @@ class OptimizedClassDescriptor { } /** + * Returns class fields. + * + * @return Fields. + */ + public Fields fields() { + return fields; + } + + /** * @param cls Class. * @return Type. */ @@ -860,7 +846,7 @@ class OptimizedClassDescriptor { * Information about one field. */ @SuppressWarnings("PackageVisibleInnerClass") - static class FieldInfo { + public static class FieldInfo { /** Field. */ private final Field field; @@ -891,6 +877,20 @@ class OptimizedClassDescriptor { } /** + * @return Field ID. + */ + public int id() { + return fieldId; + } + + /** + * @return Type. + */ + public OptimizedFieldType type() { + return fieldType; + } + + /** * @return Returns field. */ Field field() { @@ -905,31 +905,17 @@ class OptimizedClassDescriptor { } /** - * @return Type. - */ - OptimizedFieldType type() { - return fieldType; - } - - /** * @return Name. */ String name() { return fieldName; } - - /** - * @return Field ID. - */ - int id() { - return fieldId; - } } /** * Information about one class. */ - static class ClassFields { + public static class ClassFields { /** Fields. */ private final List<FieldInfo> fields; @@ -979,13 +965,22 @@ class OptimizedClassDescriptor { return nameToIndex.get(name); } + + /** + * Returns field info list. + * + * @return Fields info list. + */ + public List<FieldInfo> fieldInfoList() { + return fields; + } } /** * Encapsulates data about class fields. */ @SuppressWarnings("PackageVisibleInnerClass") - static class Fields { + public static class Fields { /** Fields. */ private final List<ClassFields> fields; @@ -993,16 +988,16 @@ class OptimizedClassDescriptor { private final List<Field> ownFields; /** Fields indexing flag. */ - private final boolean fieldsIndexingEnabled; + private final boolean fieldsIndexingSupported; /** * Creates new instance. * * @param fields Fields. */ - Fields(List<ClassFields> fields, boolean fieldsIndexingEnabled) { + Fields(List<ClassFields> fields, boolean fieldsIndexingSupported) { this.fields = fields; - this.fieldsIndexingEnabled = fieldsIndexingEnabled; + this.fieldsIndexingSupported = fieldsIndexingSupported; if (fields.isEmpty()) ownFields = null; @@ -1036,21 +1031,21 @@ class OptimizedClassDescriptor { } /** - * Whether fields indexing is enabled for a given object or not. + * Whether fields indexing is supported for a given object or not. * - * @return {@code true} if enabled, {@code false} otherwise. + * @return {@code true} if supported, {@code false} otherwise. */ - boolean fieldsIndexingEnabled() { - return fieldsIndexingEnabled; + public boolean fieldsIndexingSupported() { + return fieldsIndexingSupported; } /** - * Returns a total number of hierarchy levels. + * Returns fields list. * - * @return number of hierarchy levels. + * @return Fields list. */ - int hierarchyLevels() { - return fields.size(); + public List<ClassFields> fieldsList() { + return fields; } } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldType.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldType.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldType.java index 3840dfd..0fbf53c 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldType.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedFieldType.java @@ -20,7 +20,7 @@ package org.apache.ignite.marshaller.optimized; /** * Field type used to calculate {@code Unsafe} offsets into objects. */ -enum OptimizedFieldType { +public enum OptimizedFieldType { /** */ BYTE, http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshaller.java index 4e5b1a7..a5b0cc4 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshaller.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshaller.java @@ -77,19 +77,16 @@ import java.util.concurrent.*; */ public class OptimizedMarshaller extends AbstractMarshaller { /** Default class loader. */ - private final ClassLoader dfltClsLdr = getClass().getClassLoader(); + protected final ClassLoader dfltClsLdr = getClass().getClassLoader(); /** Whether or not to require an object to be serializable in order to be marshalled. */ - private boolean requireSer = true; + protected boolean requireSer = true; /** ID mapper. */ - private OptimizedMarshallerIdMapper mapper; - - /** Metadata handler. */ - private OptimizedObjectMetadataHandler metaHandler; + protected OptimizedMarshallerIdMapper mapper; /** Class descriptors by class. */ - private final ConcurrentMap<Class, OptimizedClassDescriptor> clsMap = new ConcurrentHashMap8<>(); + protected final ConcurrentMap<Class, OptimizedClassDescriptor> clsMap = new ConcurrentHashMap8<>(); /** * Creates new marshaller will all defaults. @@ -131,20 +128,10 @@ public class OptimizedMarshaller extends AbstractMarshaller { } /** - * Sets metadata handler. - * - * @param metaHandler Metadata handler. - */ - public void setMetadataHandler(OptimizedObjectMetadataHandler metaHandler) { - this.metaHandler = metaHandler; - } - - /** * Specifies size of cached object streams used by marshaller. Object streams are cached for * performance reason to avoid costly recreation for every serialization routine. If {@code 0} (default), * pool is not used and each thread has its own cached object stream which it keeps reusing. * <p> - * * Since each stream has an internal buffer, creating a stream for each thread can lead to * high memory consumption if many large messages are marshalled or unmarshalled concurrently. * Consider using pool in this case. This will limit number of streams that can be created and, @@ -168,7 +155,7 @@ public class OptimizedMarshaller extends AbstractMarshaller { try { objOut = OptimizedObjectStreamRegistry.out(); - objOut.context(clsMap, ctx, mapper, metaHandler, requireSer); + objOut.context(clsMap, ctx, mapper, requireSer); objOut.out().outputStream(out); @@ -189,7 +176,7 @@ public class OptimizedMarshaller extends AbstractMarshaller { try { objOut = OptimizedObjectStreamRegistry.out(); - objOut.context(clsMap, ctx, mapper, metaHandler, requireSer); + objOut.context(clsMap, ctx, mapper, requireSer); objOut.writeObject(obj); @@ -213,7 +200,7 @@ public class OptimizedMarshaller extends AbstractMarshaller { try { objIn = OptimizedObjectStreamRegistry.in(); - objIn.context(clsMap, ctx, mapper, metaHandler, clsLdr != null ? clsLdr : dfltClsLdr); + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr); objIn.in().inputStream(in); @@ -242,7 +229,7 @@ public class OptimizedMarshaller extends AbstractMarshaller { try { objIn = OptimizedObjectStreamRegistry.in(); - objIn.context(clsMap, ctx, mapper, metaHandler, clsLdr != null ? clsLdr : dfltClsLdr); + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr); objIn.in().bytes(arr, arr.length); @@ -261,54 +248,6 @@ public class OptimizedMarshaller extends AbstractMarshaller { } } - //TODO: - public <T> T unmarshal(String fieldName, byte[] arr, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { - assert arr != null && fieldName != null; - - OptimizedObjectInputStream objIn = null; - - try { - objIn = OptimizedObjectStreamRegistry.in(); - - objIn.context(clsMap, ctx, mapper, metaHandler, clsLdr != null ? clsLdr : dfltClsLdr); - - objIn.in().bytes(arr, arr.length); - - return (T)objIn.readField(fieldName); - } - catch (IOException e) { - throw new IgniteCheckedException("Failed to deserialize object with given class loader: " + clsLdr, e); - } - catch (ClassNotFoundException e) { - throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + - "(make sure same version of all classes are available on all nodes or enable peer-class-loading): " + - clsLdr, e); - } - finally { - OptimizedObjectStreamRegistry.closeIn(objIn); - } - } - - /** - * Checks whether a footer injection into a serialized form of the object is supported. - * Footer contains information on fields location in the serialized form, thus enabling fast queries without a need - * to deserialize the object. - * - * @param obj Object. - * @return {@code true} if the footer is supported. - */ - public boolean footerSupported(Object obj) throws IgniteCheckedException { - try { - OptimizedClassDescriptor desc = OptimizedMarshallerUtils.classDescriptor(clsMap, obj.getClass(), ctx, - mapper, metaHandler, true); - - return metaHandler.metadata(desc.typeId()) != null; - } - catch (IOException e) { - throw new IgniteCheckedException("Failed to get class descriptor.", e); - } - } - /** * Checks whether {@code GridOptimizedMarshaller} is able to work on the current JVM. * <p> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java index 138e732..61cbcee 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerUtils.java @@ -34,7 +34,7 @@ import java.util.concurrent.*; /** * Miscellaneous utility methods to facilitate {@link OptimizedMarshaller}. */ -class OptimizedMarshallerUtils { +public class OptimizedMarshallerUtils { /** */ private static final Unsafe UNSAFE = GridUnsafe.unsafe(); @@ -141,16 +141,7 @@ class OptimizedMarshallerUtils { static final byte EXTERNALIZABLE = 101; /** */ - static final byte SERIALIZABLE = 102; - - /** */ - static final byte EMPTY_FOOTER = -1; - - /** */ - static final byte FOOTER_LEN_OFF = 4; - - /** */ - static final byte VARIABLE_LEN = -1; + public static final byte SERIALIZABLE = 102; /** UTF-8 character name. */ static final Charset UTF_8 = Charset.forName("UTF-8"); @@ -180,19 +171,14 @@ class OptimizedMarshallerUtils { * @param cls Class. * @param ctx Context. * @param mapper ID mapper. - * @param metaHandler Metadata handler. - * @param tryEnableMeta Try to enable meta during {@code OptimizedClassDescriptor} registration. Meta is supported, - * only for objects that support footer injection is their serialized form. * @return Descriptor. * @throws IOException In case of error. */ - static OptimizedClassDescriptor classDescriptor( + public static OptimizedClassDescriptor classDescriptor( ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, Class cls, MarshallerContext ctx, - OptimizedMarshallerIdMapper mapper, - OptimizedObjectMetadataHandler metaHandler, - boolean tryEnableMeta) + OptimizedMarshallerIdMapper mapper) throws IOException { OptimizedClassDescriptor desc = clsMap.get(cls); @@ -209,8 +195,7 @@ class OptimizedMarshallerUtils { throw new IOException("Failed to register class: " + cls.getName(), e); } - desc = new OptimizedClassDescriptor(cls, registered ? typeId : 0, clsMap, ctx, mapper, metaHandler, - tryEnableMeta); + desc = new OptimizedClassDescriptor(cls, registered ? typeId : 0, clsMap, ctx, mapper); if (registered) { OptimizedClassDescriptor old = clsMap.putIfAbsent(cls, desc); @@ -247,7 +232,7 @@ class OptimizedMarshallerUtils { * @param fieldName Field name. * @return Field ID. */ - static int resolveFieldId(String fieldName) { + public static int resolveFieldId(String fieldName) { return fieldName.hashCode(); } @@ -259,7 +244,6 @@ class OptimizedMarshallerUtils { * @param ldr Class loader. * @param ctx Context. * @param mapper ID mapper. - * @param metaHandler Metadata handler. * @return Descriptor. * @throws IOException In case of error. * @throws ClassNotFoundException If class was not found. @@ -269,8 +253,7 @@ class OptimizedMarshallerUtils { int id, ClassLoader ldr, MarshallerContext ctx, - OptimizedMarshallerIdMapper mapper, - OptimizedObjectMetadataHandler metaHandler) throws IOException, ClassNotFoundException { + OptimizedMarshallerIdMapper mapper) throws IOException, ClassNotFoundException { Class cls; try { @@ -284,8 +267,7 @@ class OptimizedMarshallerUtils { if (desc == null) { OptimizedClassDescriptor old = clsMap.putIfAbsent(cls, desc = - new OptimizedClassDescriptor(cls, resolveTypeId(cls.getName(), mapper), clsMap, ctx, mapper, - metaHandler, false)); + new OptimizedClassDescriptor(cls, resolveTypeId(cls.getName(), mapper), clsMap, ctx, mapper)); if (old != null) desc = old; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java index 70a2f3f..7d1cad0 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java @@ -34,7 +34,7 @@ import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; /** * Optimized object input stream. */ -class OptimizedObjectInputStream extends ObjectInputStream { +public class OptimizedObjectInputStream extends ObjectInputStream { /** Unsafe. */ private static final Unsafe UNSAFE = GridUnsafe.unsafe(); @@ -42,19 +42,19 @@ class OptimizedObjectInputStream extends ObjectInputStream { private static final Object DUMMY = new Object(); /** */ - private final HandleTable handles = new HandleTable(10); + protected MarshallerContext ctx; /** */ - private MarshallerContext ctx; + protected OptimizedMarshallerIdMapper mapper; /** */ - private OptimizedMarshallerIdMapper mapper; + protected ClassLoader clsLdr; /** */ - private ClassLoader clsLdr; + protected GridDataInput in; /** */ - private GridDataInput in; + protected ConcurrentMap<Class, OptimizedClassDescriptor> clsMap; /** */ private Object curObj; @@ -66,16 +66,13 @@ class OptimizedObjectInputStream extends ObjectInputStream { private Class<?> curCls; /** */ - private ConcurrentMap<Class, OptimizedClassDescriptor> clsMap; - - /** */ - private OptimizedObjectMetadataHandler metaHandler; + private final HandleTable handles = new HandleTable(10); /** * @param in Input. * @throws IOException In case of error. */ - OptimizedObjectInputStream(GridDataInput in) throws IOException { + protected OptimizedObjectInputStream(GridDataInput in) throws IOException { this.in = in; } @@ -83,21 +80,18 @@ class OptimizedObjectInputStream extends ObjectInputStream { * @param clsMap Class descriptors by class map. * @param ctx Context. * @param mapper ID mapper. - * @param metaHandler Metadata handler. * @param clsLdr Class loader. */ - void context( + protected void context( ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, MarshallerContext ctx, OptimizedMarshallerIdMapper mapper, - OptimizedObjectMetadataHandler metaHandler, ClassLoader clsLdr) { this.clsMap = clsMap; this.ctx = ctx; this.mapper = mapper; this.clsLdr = clsLdr; - this.metaHandler = metaHandler; } /** @@ -250,8 +244,8 @@ class OptimizedObjectInputStream extends ObjectInputStream { int typeId = readInt(); OptimizedClassDescriptor desc = typeId == 0 ? - classDescriptor(clsMap, U.forName(readUTF(), clsLdr), ctx, mapper, metaHandler, false): - classDescriptor(clsMap, typeId, clsLdr, ctx, mapper, metaHandler); + classDescriptor(clsMap, U.forName(readUTF(), clsLdr), ctx, mapper): + classDescriptor(clsMap, typeId, clsLdr, ctx, mapper); curCls = desc.describedClass(); @@ -281,7 +275,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { int compTypeId = readInt(); return compTypeId == 0 ? U.forName(readUTF(), clsLdr) : - classDescriptor(clsMap, compTypeId, clsLdr, ctx, mapper, metaHandler).describedClass(); + classDescriptor(clsMap, compTypeId, clsLdr, ctx, mapper).describedClass(); } /** @@ -358,7 +352,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { switch ((t.type())) { case BYTE: - readByte(); //type + readFieldType(); byte resByte = readByte(); @@ -368,7 +362,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case SHORT: - readByte(); //type + readFieldType(); short resShort = readShort(); @@ -378,7 +372,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case INT: - readByte(); //type + readFieldType(); int resInt = readInt(); @@ -388,7 +382,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case LONG: - readByte(); //type + readFieldType(); long resLong = readLong(); @@ -398,7 +392,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case FLOAT: - readByte(); //type + readFieldType(); float resFloat = readFloat(); @@ -408,7 +402,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case DOUBLE: - readByte(); //type + readFieldType(); double resDouble = readDouble(); @@ -418,7 +412,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case CHAR: - readByte(); //type + readFieldType(); char resChar = readChar(); @@ -428,7 +422,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { break; case BOOLEAN: - readByte(); //type + readFieldType(); boolean resBoolean = readBoolean(); @@ -540,12 +534,7 @@ class OptimizedObjectInputStream extends ObjectInputStream { } } - if (metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != null) { - int footerLen = in.readInt(); - - if (footerLen != EMPTY_FOOTER) - in.skipBytes(footerLen - 4); - } + readFooter(cls); return obj; } @@ -946,126 +935,34 @@ class OptimizedObjectInputStream extends ObjectInputStream { return new GetFieldImpl(this); } - /** {@inheritDoc} */ - @Override public void registerValidation(ObjectInputValidation obj, int pri) { - // No-op. - } - - /** {@inheritDoc} */ - @Override public int available() throws IOException { - return -1; - } - /** - * Checks whether the object has a field with name {@code fieldName}. + * Reads object footer from the underlying stream. * - * @param fieldName Field name. - * @return {@code true} if field exists, {@code false} otherwise. - * @throws IOException in case of error. - */ - public boolean hasField(String fieldName) throws IOException { - int pos = in.position(); - - // TODO: IGNITE-950, do we need move to start position? - if (in.readByte() != SERIALIZABLE) { - in.position(pos); - return false; - } - - FieldRange range = fieldRange(fieldName); - - in.position(pos); - - return range != null && range.start > 0; - } - - /** - * TODO: IGNITE-950 - * @param fieldName - * @return - * @throws IOException - * @throws ClassNotFoundException + * @param cls Class. + * @throws IOException In case of error. */ - Object readField(String fieldName) throws IOException, ClassNotFoundException { - int pos = in.position(); - - // TODO: IGNITE-950, do we need move to start position? - if (in.readByte() != SERIALIZABLE) { - in.position(pos); - return false; - } - - FieldRange range = fieldRange(fieldName); - - Object obj = null; - - if (range != null && range.start > 0) { - in.position(range.start); - obj = readObject(); - } - - in.position(pos); - - return obj; + protected void readFooter(Class<?> cls) throws IOException { + // No-op } /** - * Returns field offset in the byte stream. + * Reads field's type during its deserialization. * - * @param fieldName Field name. - * @return positive range or {@code null} if the object doesn't have such a field. - * @throws IOException in case of error. + * @return Field type. + * @throws IOException In case of error. */ - private FieldRange fieldRange(String fieldName) throws IOException { - int fieldId = resolveFieldId(fieldName); - - int typeId = readInt(); - - int clsNameLen = 0; - - if (typeId == 0) { - int pos = in.position(); - - typeId = OptimizedMarshallerUtils.resolveTypeId(readUTF(), mapper); - - clsNameLen = in.position() - pos; - } - - OptimizedObjectMetadata meta = metaHandler.metadata(typeId); - - if (meta == null) - // TODO: IGNITE-950 add warning! - return null; - - int end = in.size(); - - in.position(end - FOOTER_LEN_OFF); - - int footerLen = in.readInt(); - - if (footerLen == EMPTY_FOOTER) - return null; - - // 4 - skipping length at the beginning - int footerOff = (end - footerLen) + 4; - in.position(footerOff); - - int fieldOff = 0; - - for (OptimizedObjectMetadata.FieldInfo info : meta.getMeta()) { - if (info.id == fieldId) { - //object header len: 1 - for type, 4 - for type ID, 2 - for checksum. - fieldOff += 1 + 4 + clsNameLen + 2; - - FieldRange range = new FieldRange(fieldOff, info.len == VARIABLE_LEN ? in.readShort() : info.len); + protected int readFieldType() throws IOException { + return 0; + } - return range; - } - else - fieldOff += info.len == VARIABLE_LEN ? in.readShort() : info.len; - } + /** {@inheritDoc} */ + @Override public void registerValidation(ObjectInputValidation obj, int pri) { + // No-op. + } - return null; + /** {@inheritDoc} */ + @Override public int available() throws IOException { + return -1; } /** @@ -1185,56 +1082,56 @@ class OptimizedObjectInputStream extends ObjectInputStream { switch (t.type()) { case BYTE: - in.readByte(); //type + in.readFieldType(); obj = in.readByte(); break; case SHORT: - in.readByte(); //type + in.readFieldType(); obj = in.readShort(); break; case INT: - in.readByte(); //type + in.readFieldType(); obj = in.readInt(); break; case LONG: - in.readByte(); //type + in.readFieldType(); obj = in.readLong(); break; case FLOAT: - in.readByte(); //type + in.readFieldType(); obj = in.readFloat(); break; case DOUBLE: - in.readByte(); //type + in.readFieldType(); obj = in.readDouble(); break; case CHAR: - in.readByte(); //type + in.readFieldType(); obj = in.readChar(); break; case BOOLEAN: - in.readByte(); //type + in.readFieldType(); obj = in.readBoolean(); @@ -1313,24 +1210,4 @@ class OptimizedObjectInputStream extends ObjectInputStream { return objs[fieldInfo.getIndex(name)] != null ? (T)objs[fieldInfo.getIndex(name)] : dflt; } } - - /** - * - */ - private static class FieldRange { - /** */ - private int start; - - /** */ - private int len; - - /** - * @param start Start. - * @param len Length. - */ - public FieldRange(int start, int len) { - this.start = start; - this.len = len; - } - } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java deleted file mode 100644 index 5b476da..0000000 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.marshaller.optimized; - -import org.apache.ignite.*; - -import java.io.*; -import java.util.*; - -import static org.apache.ignite.marshaller.optimized.OptimizedFieldType.*; -/** - * Metadata that keeps fields information. Used in conjunction with the footer that is added to some objects during - * marshalling. - */ -public class OptimizedObjectMetadata implements Externalizable { - /** */ - private List<FieldInfo> fieldsInfo; - - /** Constructor. */ - public OptimizedObjectMetadata() { - // No-op - } - - /** - * Adds meta for a new field. - * - * @param fieldId Field ID. - * @param fieldType Field type. - */ - public void addMeta(int fieldId, OptimizedFieldType fieldType) { - if (fieldsInfo == null) - fieldsInfo = new ArrayList<>(); - - int len = 1; - - switch (fieldType) { - case BYTE: - case BOOLEAN: - len += 1; - break; - - case SHORT: - case CHAR: - len += 2; - break; - - case INT: - case FLOAT: - len += 4; - break; - - case LONG: - case DOUBLE: - len += 8; - break; - - case OTHER: - len = OptimizedMarshallerUtils.VARIABLE_LEN; - break; - - default: - throw new IgniteException("Unknown field type: " + fieldType); - } - - assert len != 1; - - fieldsInfo.add(new FieldInfo(fieldId, len)); - } - - /** - * Gets {@link org.apache.ignite.marshaller.optimized.OptimizedObjectMetadata.FieldInfo} at the {@code index}. - * - * @param index Position. - * @return Field meta info. - */ - public FieldInfo getMeta(int index) { - return fieldsInfo.get(index); - } - /** - * Returns all the metadata stored for the object. - * - * @return Metadata collection. - */ - public List<FieldInfo> getMeta() { - return Collections.unmodifiableList(fieldsInfo); - } - - /** {@inheritDoc} */ - @Override public void writeExternal(ObjectOutput out) throws IOException { - if (fieldsInfo == null) { - out.writeInt(0); - return; - } - - out.writeInt(fieldsInfo.size()); - - for (FieldInfo fieldInfo : fieldsInfo) { - out.writeInt(fieldInfo.id); - out.writeInt(fieldInfo.len); - } - } - - /** {@inheritDoc} */ - @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - int size = in.readInt(); - - fieldsInfo = new ArrayList<>(size); - - for (int i = 0; i < size; i++) - fieldsInfo.add(new FieldInfo(in.readInt(), in.readInt())); - } - - /** - * Field info. - */ - public static class FieldInfo { - /** Field ID. */ - int id; - - /** Field type. */ - int len; - - /** - * Constructor. - * - * @param id Field ID. - * @param len Field len. - */ - public FieldInfo(int id, int len) { - this.id = id; - this.len = len; - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataHandler.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataHandler.java deleted file mode 100644 index a5d54dd..0000000 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.marshaller.optimized; - -/** - * Metadata handler for optimized objects. - */ -public interface OptimizedObjectMetadataHandler { - /** - * Adds meta data. - * - * @param typeId Type ID. - * @param meta Meta data. - */ - void addMeta(int typeId, OptimizedObjectMetadata meta); - - - /** - * Gets meta data for provided type ID. - * - * @param typeId Type ID. - * @return Meta data. - */ - OptimizedObjectMetadata metadata(int typeId); -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java deleted file mode 100644 index ee85754..0000000 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadataKey.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.marshaller.optimized; - -import org.apache.ignite.internal.processors.cache.*; - -import java.io.*; - -/** - * Optimized object metadata key. - */ -public class OptimizedObjectMetadataKey extends GridCacheUtilityKey<OptimizedObjectMetadataKey> - implements Externalizable { - /** */ - private static final long serialVersionUID = 0L; - - /** */ - private int typeId; - - /** - * For {@link Externalizable}. - */ - public OptimizedObjectMetadataKey() { - // No-op - } - - /** - * Constructor. - * - * @param typeId Type id. - */ - public OptimizedObjectMetadataKey(int typeId) { - this.typeId = typeId; - } - - /** {@inheritDoc} */ - @Override public void writeExternal(ObjectOutput out) throws IOException { - out.writeInt(typeId); - } - - /** {@inheritDoc} */ - @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - typeId = in.readInt(); - } - - /** {@inheritDoc} */ - @Override protected boolean equalsx(OptimizedObjectMetadataKey key) { - return typeId == key.typeId; - } - - /** {@inheritDoc} */ - @Override public int hashCode() { - return typeId; - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java index 05d3e3d..a88da95 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java @@ -34,7 +34,7 @@ import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; /** * Optimized object output stream. */ -class OptimizedObjectOutputStream extends ObjectOutputStream { +public class OptimizedObjectOutputStream extends ObjectOutputStream { /** */ private static final Collection<String> CONVERTED_ERR = F.asList( "weblogic/management/ManagementException", @@ -43,19 +43,22 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { ); /** */ - private final GridHandleTable handles = new GridHandleTable(10, 3.00f); + protected final GridDataOutput out; /** */ - private final GridDataOutput out; + protected MarshallerContext ctx; /** */ - private MarshallerContext ctx; + protected OptimizedMarshallerIdMapper mapper; /** */ - private OptimizedMarshallerIdMapper mapper; + protected ConcurrentMap<Class, OptimizedClassDescriptor> clsMap; /** */ - private boolean requireSer; + protected boolean requireSer; + + /** */ + private final GridHandleTable handles = new GridHandleTable(10, 3.00f); /** */ private Object curObj; @@ -69,17 +72,11 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { /** */ private PutFieldImpl curPut; - /** */ - private ConcurrentMap<Class, OptimizedClassDescriptor> clsMap; - - /** */ - private OptimizedObjectMetadataHandler metaHandler; - /** * @param out Output. * @throws IOException In case of error. */ - OptimizedObjectOutputStream(GridDataOutput out) throws IOException { + protected OptimizedObjectOutputStream(GridDataOutput out) throws IOException { this.out = out; } @@ -87,18 +84,15 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { * @param clsMap Class descriptors by class map. * @param ctx Context. * @param mapper ID mapper. - * @param metaHandler Metadata handler. * @param requireSer Require {@link Serializable} flag. */ - void context(ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, + protected void context(ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, MarshallerContext ctx, OptimizedMarshallerIdMapper mapper, - OptimizedObjectMetadataHandler metaHandler, boolean requireSer) { this.clsMap = clsMap; this.ctx = ctx; this.mapper = mapper; - this.metaHandler = metaHandler; this.requireSer = requireSer; } @@ -193,9 +187,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { clsMap, obj instanceof Object[] ? Object[].class : obj.getClass(), ctx, - mapper, - metaHandler, - false); + mapper); if (desc.excluded()) { writeByte(NULL); @@ -220,9 +212,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { desc = classDescriptor(clsMap, obj instanceof Object[] ? Object[].class : obj.getClass(), ctx, - mapper, - metaHandler, - false); + mapper); } if (handle >= 0) { @@ -319,11 +309,10 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { @SuppressWarnings("ForLoopReplaceableByForEach") void writeSerializable(Object obj, List<Method> mtds, OptimizedClassDescriptor.Fields fields, int headerPos) throws IOException { - Footer footer = null; - - if (metaHandler.metadata(resolveTypeId(obj.getClass().getName(), mapper)) != null) { - footer = new Footer(fields); + Footer footer = createFooter(obj.getClass()); + if (footer != null) { + footer.fields(fields); footer.headerPos(headerPos); } @@ -494,7 +483,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { switch (t.type()) { case BYTE: if (t.field() != null) { - writeByte(BYTE); + writeFieldType(BYTE); writeByte(getByte(obj, t.offset())); } @@ -502,7 +491,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case SHORT: if (t.field() != null) { - writeByte(SHORT); + writeFieldType(SHORT); writeShort(getShort(obj, t.offset())); } @@ -510,7 +499,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case INT: if (t.field() != null) { - writeByte(INT); + writeFieldType(INT); writeInt(getInt(obj, t.offset())); } @@ -518,7 +507,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case LONG: if (t.field() != null) { - writeByte(LONG); + writeFieldType(LONG); writeLong(getLong(obj, t.offset())); } @@ -526,7 +515,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case FLOAT: if (t.field() != null) { - writeByte(FLOAT); + writeFieldType(FLOAT); writeFloat(getFloat(obj, t.offset())); } @@ -534,7 +523,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case DOUBLE: if (t.field() != null) { - writeByte(DOUBLE); + writeFieldType(DOUBLE); writeDouble(getDouble(obj, t.offset())); } @@ -542,7 +531,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case CHAR: if (t.field() != null) { - writeByte(CHAR); + writeFieldType(CHAR); writeChar(getChar(obj, t.offset())); } @@ -550,7 +539,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { case BOOLEAN: if (t.field() != null) { - writeByte(BOOLEAN); + writeFieldType(BOOLEAN); writeBoolean(getBoolean(obj, t.offset())); } @@ -561,7 +550,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { int handle = writeObject0(getObject(obj, t.offset())); if (footer != null && handle >= 0) - footer.disable(); + footer.putHandle(t.id(), handle); } } @@ -770,49 +759,49 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { switch (t.get1().type()) { case BYTE: - writeByte(BYTE); + writeFieldType(BYTE); writeByte((Byte)t.get2()); break; case SHORT: - writeByte(SHORT); + writeFieldType(SHORT); writeShort((Short)t.get2()); break; case INT: - writeByte(INT); + writeFieldType(INT); writeInt((Integer)t.get2()); break; case LONG: - writeByte(LONG); + writeFieldType(LONG); writeLong((Long)t.get2()); break; case FLOAT: - writeByte(FLOAT); + writeFieldType(FLOAT); writeFloat((Float)t.get2()); break; case DOUBLE: - writeByte(DOUBLE); + writeFieldType(DOUBLE); writeDouble((Double)t.get2()); break; case CHAR: - writeByte(CHAR); + writeFieldType(CHAR); writeChar((Character)t.get2()); break; case BOOLEAN: - writeByte(BOOLEAN); + writeFieldType(BOOLEAN); writeBoolean((Boolean)t.get2()); break; @@ -821,7 +810,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { int handle = writeObject0(t.get2()); if (footer != null && handle >= 0) - footer.disable(); + footer.putHandle(t.get1().id(), handle); } if (footer != null) { @@ -853,6 +842,26 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { } /** + * Writes field's type to an OutputStream during field serialization. + * + * @param type Field type. + * @throws IOException If error. + */ + protected void writeFieldType(byte type) throws IOException { + // No-op + } + + /** + * Creates new instance of {@code Footer}. + * + * @param cls Class. + * @return {@code Footer} instance. + */ + protected Footer createFooter(Class<?> cls) { + return null; + } + + /** * Returns objects that were added to handles table. * Used ONLY for test purposes. * @@ -960,79 +969,44 @@ class OptimizedObjectOutputStream extends ObjectOutputStream { /** * */ - private class Footer { - /** */ - private ArrayList<Short> data; - - /** */ - private int headerPos; - + protected interface Footer { /** - * Constructor. + * Sets fields. * * @param fields Fields. */ - private Footer(OptimizedClassDescriptor.Fields fields) { - if (fields.fieldsIndexingEnabled()) - data = new ArrayList<>(); - else - data = null; - } + void fields(OptimizedClassDescriptor.Fields fields); /** * Sets field's header absolute position. * * @param pos Absolute position. */ - private void headerPos(int pos) { - headerPos = pos; - } + void headerPos(int pos); /** * Puts type ID and its value len to the footer. * - * @param fieldId Field ID. + * @param fieldId Field ID. * @param fieldType Field type. - * @param len Total number of bytes occupied by type's value. + * @param len Total number of bytes occupied by type's value. */ - private void put(int fieldId, OptimizedFieldType fieldType, int len) { - if (data == null) - return; + void put(int fieldId, OptimizedFieldType fieldType, int len); - // Considering that field's length will be no longer 2^15 (32 MB) - if (fieldType == OptimizedFieldType.OTHER) - data.add((short)len); - } /** - * Disable footer and indexing for the given Object. + * Puts handle ID for the given field ID. + * + * @param fieldId Field ID. + * @param handleId Handle ID. */ - private void disable() { - data = null; - } + void putHandle(int fieldId, int handleId); /** * Writes footer content to the OutputStream. * * @throws IOException In case of error. */ - private void write() throws IOException { - if (data == null) - writeInt(EMPTY_FOOTER); - else { - //12 - 4 bytes for len at the beginning, 4 bytes for len at the end, 4 bytes for object len. - int footerLen = data.size() * 2 + 12; - - writeInt(footerLen); - - for (short fieldLen : data) - writeShort(fieldLen); - - // object total len - writeInt((out.size() - headerPos) + 8); - - writeInt(footerLen); - } - } + void write() throws IOException; } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExt.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExt.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExt.java new file mode 100644 index 0000000..8636566 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExt.java @@ -0,0 +1,291 @@ +/* + * 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.marshaller.optimized.ext; + +import org.apache.ignite.*; +import org.apache.ignite.internal.processors.cache.*; +import org.apache.ignite.marshaller.optimized.*; +import org.jetbrains.annotations.*; + +import java.io.*; + +import static org.apache.ignite.marshaller.optimized.OptimizedClassDescriptor.*; +import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; + +/** + * TODO + */ +public class OptimizedMarshallerExt extends OptimizedMarshaller { + /** */ + static final byte EMPTY_FOOTER = -1; + + /** */ + static final byte FOOTER_LEN_OFF = 4; + + /** */ + static final byte VARIABLE_LEN = -1; + + /** */ + private OptimizedMarshallerExtMetaHandler metaHandler; + + /** + * Creates new marshaller providing whether it should + * require {@link Serializable} interface or not. + * + * @param requireSer Whether to require {@link Serializable}. + */ + public OptimizedMarshallerExt(boolean requireSer) { + super(requireSer); + } + + /** + * Sets metadata handler. + * + * @param metaHandler Metadata handler. + */ + public void setMetadataHandler(OptimizedMarshallerExtMetaHandler metaHandler) { + this.metaHandler = metaHandler; + } + + /** + * Stores metadata information for the given {@link Class}. If the metadata is stored then a footer will be added + * during marshalling of an object of the given {@link Class} to the end of its serialized form. + * + * @param cls Class. + * @return {@code true} if the metadata has been added successfully and the footer will be written to the end of + * Object's serialized form. + * @throws IgniteCheckedException In case of error. + */ + public boolean putMetaForClass(Class<?> cls) throws IgniteCheckedException { + assert metaHandler != null; + + try { + OptimizedClassDescriptor desc = OptimizedMarshallerUtils.classDescriptor(clsMap, cls, ctx, mapper); + + if (desc.fields().fieldsIndexingSupported()) { + if (metaHandler.metadata(desc.typeId()) != null) + return true; + + OptimizedObjectMetadata meta = new OptimizedObjectMetadata(); + + for (ClassFields clsFields : desc.fields().fieldsList()) + for (FieldInfo info : clsFields.fieldInfoList()) + meta.addMeta(info.id(), info.type()); + + metaHandler.addMeta(desc.typeId(), meta); + + return true; + } + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to put meta for class: " + cls.getName(), e); + } + + return false; + } + + /** + * Checks whether a metadata is stored for the given {@link Class}. If it's stored then a footer is injected into + * a serialized form of the object of this {@link Class}. + * Footer contains information on fields location in the serialized form, thus enabling fast queries without a need + * to deserialize the object. + * + * @param cls Class. + * @return {@code true} if the metadata exists and the footer will be written to the end of Object's serialized + * form. + */ + public boolean metaSupported(Class<?> cls) throws IgniteCheckedException { + return metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != null; + } + + /** {@inheritDoc} */ + @Override public void marshal(@Nullable Object obj, OutputStream out) throws IgniteCheckedException { + assert out != null; + + OptimizedObjectOutputStreamExt objOut = null; + + try { + objOut = OptimizedObjectStreamExtRegistry.out(); + + objOut.context(clsMap, ctx, mapper, requireSer, metaHandler); + + objOut.out().outputStream(out); + + objOut.writeObject(obj); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to serialize object: " + obj, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeOut(objOut); + } + } + + /** {@inheritDoc} */ + @Override public byte[] marshal(@Nullable Object obj) throws IgniteCheckedException { + OptimizedObjectOutputStreamExt objOut = null; + + try { + objOut = OptimizedObjectStreamExtRegistry.out(); + + objOut.context(clsMap, ctx, mapper, requireSer, metaHandler); + + objOut.writeObject(obj); + + return objOut.out().array(); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to serialize object: " + obj, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeOut(objOut); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public <T> T unmarshal(InputStream in, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { + assert in != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr, metaHandler); + + objIn.in().inputStream(in); + + return (T)objIn.readObject(); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to deserialize object with given class loader: " + clsLdr, e); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + + "(make sure same versions of all classes are available on all nodes or " + + "enable peer-class-loading): " + clsLdr, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public <T> T unmarshal(byte[] arr, @Nullable ClassLoader clsLdr) throws IgniteCheckedException { + assert arr != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr, metaHandler); + + objIn.in().bytes(arr, arr.length); + + return (T)objIn.readObject(); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to deserialize object with given class loader: " + clsLdr, e); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + + "(make sure same version of all classes are available on all nodes or" + + " enable peer-class-loading): " + clsLdr, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } + + /** + * Checks whether object, serialized to byte array {@code arr}, has a field with name {@code fieldName}. + * + * @param fieldName Field name. + * @param arr Object's serialized form. + * @param off Object's start off. + * @param len Object's len. + * @return {@code true} if field exists. + */ + public boolean hasField(String fieldName, byte[] arr, int off, int len) throws IgniteCheckedException { + assert arr != null && fieldName != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, dfltClsLdr, metaHandler); + + objIn.in().bytes(arr, off, len); + + return objIn.hasField(fieldName); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to find field with name: " + fieldName, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } + + /** + * Looks up field with the given name and returns it in one of the following representations. If the field is + * serializable and has a footer then it's not deserialized but rather returned wrapped by {@link CacheObjectImpl} + * for future processing. In all other cases the field is fully deserialized. + * + * @param fieldName Field name. + * @param arr Object's serialized form. + * @param off Object's start offset. + * @param len Object's len. + * @param clsLdr Class loader. + * @param <T> Expected field class. + * @return Field. + * @throws IgniteCheckedException In case of error. + */ + public <T> T readField(String fieldName, byte[] arr, int off, int len, @Nullable ClassLoader clsLdr) + throws IgniteCheckedException { + + assert arr != null && fieldName != null; + + OptimizedObjectInputStreamExt objIn = null; + + try { + objIn = OptimizedObjectStreamExtRegistry.in(); + + objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : dfltClsLdr, metaHandler); + + objIn.in().bytes(arr, off, len); + + return objIn.readField(fieldName); + } + catch (IOException e) { + throw new IgniteCheckedException("Failed to find field with name: " + fieldName, e); + } + catch (ClassNotFoundException e) { + throw new IgniteCheckedException("Failed to find class with given class loader for unmarshalling " + + "(make sure same version of all classes are available on all nodes or" + + " enable peer-class-loading): " + clsLdr, e); + } + finally { + OptimizedObjectStreamExtRegistry.closeIn(objIn); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtMetaHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtMetaHandler.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtMetaHandler.java new file mode 100644 index 0000000..ea3b70f --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtMetaHandler.java @@ -0,0 +1,40 @@ +/* + * 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.marshaller.optimized.ext; + +/** + * Metadata handler for optimized objects. + */ +public interface OptimizedMarshallerExtMetaHandler { + /** + * Adds meta data. + * + * @param typeId Type ID. + * @param meta Meta data. + */ + void addMeta(int typeId, OptimizedObjectMetadata meta); + + + /** + * Gets meta data for provided type ID. + * + * @param typeId Type ID. + * @return Meta data. + */ + OptimizedObjectMetadata metadata(int typeId); +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectInputStreamExt.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectInputStreamExt.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectInputStreamExt.java new file mode 100644 index 0000000..e3af580 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectInputStreamExt.java @@ -0,0 +1,212 @@ +/* + * 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.marshaller.optimized.ext; + +import org.apache.ignite.internal.processors.cache.*; +import org.apache.ignite.internal.util.io.*; +import org.apache.ignite.marshaller.*; +import org.apache.ignite.marshaller.optimized.*; + +import java.io.*; +import java.util.*; +import java.util.concurrent.*; + +import static org.apache.ignite.marshaller.optimized.ext.OptimizedMarshallerExt.*; +import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*; + + +/** + * TODO: IGNITE-950 + */ +public class OptimizedObjectInputStreamExt extends OptimizedObjectInputStream { + /** */ + private OptimizedMarshallerExtMetaHandler metaHandler; + + /** {@inheritDoc} */ + public OptimizedObjectInputStreamExt(GridDataInput in) throws IOException { + super(in); + } + + /** + * @param clsMap Class descriptors by class map. + * @param ctx Context. + * @param mapper ID mapper. + * @param clsLdr Class loader. + */ + protected void context(ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, MarshallerContext ctx, + OptimizedMarshallerIdMapper mapper, ClassLoader clsLdr, OptimizedMarshallerExtMetaHandler metaHandler) { + context(clsMap, ctx, mapper, clsLdr); + + this.metaHandler = metaHandler; + } + + /** {@inheritDoc} */ + @Override protected void readFooter(Class<?> cls) throws IOException { + if (metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != null) { + int footerLen = in.readInt(); + + if (footerLen != EMPTY_FOOTER) + in.skipBytes(footerLen - 4); + } + } + + /** {@inheritDoc} */ + @Override protected int readFieldType() throws IOException { + return in.readByte(); + } + + /** + * Checks whether the object has a field with name {@code fieldName}. + * + * @param fieldName Field name. + * @return {@code true} if field exists, {@code false} otherwise. + * @throws IOException in case of error. + */ + boolean hasField(String fieldName) throws IOException { + int pos = in.position(); + + if (in.readByte() != SERIALIZABLE) { + in.position(pos); + return false; + } + + FieldRange range = fieldRange(fieldName); + + in.position(pos); + + return range != null && range.start > 0; + } + + /** + * Looks up field with the given name and returns it in one of the following representations. If the field is + * serializable and has a footer then it's not deserialized but rather returned wrapped by {@link CacheObjectImpl} + * for future processing. In all other cases the field is fully deserialized. + * + * @param fieldName Field name. + * @return Field. + * @throws IOException In case of error. + * @throws ClassNotFoundException In case of error. + */ + <F> F readField(String fieldName) throws IOException, ClassNotFoundException { + int pos = in.position(); + + if (in.readByte() != SERIALIZABLE) { + in.position(pos); + return null; + } + + FieldRange range = fieldRange(fieldName); + + F field = null; + + if (range != null && range.start > 0) { + in.position(range.start); + + if (in.readByte() == SERIALIZABLE && metaHandler.metadata(in.readInt()) != null) { + //TODO: IGNITE-950. Optimization - don't create a copy of array, pass the old one with range. + field = (F)new CacheObjectImpl(null, Arrays.copyOfRange(in.array(), range.start, range.len)); + } + else { + in.position(range.start); + field = (F)readObject(); + } + } + + in.position(pos); + + return field; + } + + /** + * Returns field offset in the byte stream. + * + * @param fieldName Field name. + * @return positive range or {@code null} if the object doesn't have such a field. + * @throws IOException in case of error. + */ + private FieldRange fieldRange(String fieldName) throws IOException { + int fieldId = resolveFieldId(fieldName); + + int typeId = readInt(); + + int clsNameLen = 0; + + if (typeId == 0) { + int pos = in.position(); + + typeId = OptimizedMarshallerUtils.resolveTypeId(readUTF(), mapper); + + clsNameLen = in.position() - pos; + } + + OptimizedObjectMetadata meta = metaHandler.metadata(typeId); + + if (meta == null) + // TODO: IGNITE-950 add warning! + return null; + + int end = in.size(); + + in.position(end - FOOTER_LEN_OFF); + + int footerLen = in.readInt(); + + if (footerLen == EMPTY_FOOTER) + return null; + + // 4 - skipping length at the beginning + int footerOff = (end - footerLen) + 4; + in.position(footerOff); + + int fieldOff = 0; + + for (OptimizedObjectMetadata.FieldInfo info : meta.getMeta()) { + if (info.id == fieldId) { + //object header len: 1 - for type, 4 - for type ID, 2 - for checksum. + fieldOff += 1 + 4 + clsNameLen + 2; + + FieldRange range = new FieldRange(fieldOff, info.len == VARIABLE_LEN ? in.readShort() : info.len); + + return range; + } + else + fieldOff += info.len == VARIABLE_LEN ? in.readShort() : info.len; + } + + return null; + } + + /** + * + */ + private static class FieldRange { + /** */ + private int start; + + /** */ + private int len; + + /** + * @param start Start. + * @param len Length. + */ + public FieldRange(int start, int len) { + this.start = start; + this.len = len; + } + } +}
