# gg-9470-rename
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/a50fccdd Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/a50fccdd Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/a50fccdd Branch: refs/heads/master Commit: a50fccdda8e1c9fb8831182e097a1a917058c8b9 Parents: 580b2aa Author: sboikov <sboi...@gridgain.com> Authored: Thu Dec 4 21:53:27 2014 +0300 Committer: sboikov <sboi...@gridgain.com> Committed: Thu Dec 4 21:53:32 2014 +0300 ---------------------------------------------------------------------- examples/config/example-cache.xml | 2 +- examples/config/example-compute.xml | 2 +- examples/config/example-streamer.xml | 2 +- examples/config/filesystem/example-ggfs.xml | 2 +- .../MemcacheRestExampleNodeStartup.java | 2 +- .../examples/misc/springbean/spring-bean.xml | 2 +- .../GridOptimizedMarshallerAopTest.java | 1 + .../java/org/apache/ignite/IgniteCompute.java | 3 +- .../configuration/IgniteConfiguration.java | 3 +- .../java/org/apache/ignite/lang/IgniteUuid.java | 2 +- .../ignite/marshaller/GridMarshaller.java | 3 +- .../marshaller/jdk/GridJdkMarshaller.java | 3 +- .../optimized/GridOptimizedClassDescriptor.java | 1032 +++++++++++++++++ .../optimized/GridOptimizedClassResolver.java | 469 ++++++++ .../optimized/GridOptimizedFieldType.java | 42 + .../optimized/GridOptimizedMarshallable.java | 57 + .../optimized/GridOptimizedMarshaller.java | 408 +++++++ .../optimized/GridOptimizedMarshallerUtils.java | 450 ++++++++ .../GridOptimizedObjectInputStream.java | 1008 +++++++++++++++++ .../GridOptimizedObjectOutputStream.java | 831 ++++++++++++++ .../GridOptimizedObjectStreamRegistry.java | 215 ++++ .../GridClientOptimizedMarshaller.java | 4 +- .../GridCacheRendezvousAffinityFunction.java | 2 +- .../org/gridgain/grid/kernal/GridGainEx.java | 2 +- .../org/gridgain/grid/kernal/GridKernal.java | 2 +- .../org/gridgain/grid/kernal/GridTopic.java | 2 +- .../deployment/GridDeploymentLocalStore.java | 2 +- .../GridDeploymentPerLoaderStore.java | 2 +- .../GridDeploymentPerVersionStore.java | 2 +- .../affinity/GridAffinityMessage.java | 2 +- .../processors/cache/GridCacheReturn.java | 2 +- .../processors/cache/GridCacheTxEntry.java | 2 +- .../processors/cache/GridCacheVersion.java | 2 +- .../jdbc/GridCacheQueryJdbcMetadataTask.java | 2 +- .../query/jdbc/GridCacheQueryJdbcTask.java | 2 +- .../streamer/GridStreamerExecutionBatch.java | 2 +- .../optimized/GridOptimizedClassDescriptor.java | 1035 ------------------ .../optimized/GridOptimizedClassResolver.java | 471 -------- .../optimized/GridOptimizedFieldType.java | 42 - .../optimized/GridOptimizedMarshallable.java | 57 - .../optimized/GridOptimizedMarshaller.java | 410 ------- .../optimized/GridOptimizedMarshallerUtils.java | 450 -------- .../GridOptimizedObjectInputStream.java | 1008 ----------------- .../GridOptimizedObjectOutputStream.java | 831 -------------- .../GridOptimizedObjectStreamRegistry.java | 215 ---- modules/core/src/test/config/example-cache.xml | 2 +- modules/core/src/test/config/ggfs-loopback.xml | 2 +- .../core/src/test/config/ggfs-no-endpoint.xml | 2 +- modules/core/src/test/config/ggfs-shmem.xml | 2 +- .../src/test/config/io-manager-benchmark.xml | 2 +- modules/core/src/test/config/jobs-load-base.xml | 2 +- .../core/src/test/config/load/dsi-load-base.xml | 2 +- .../src/test/config/spring-start-nodes-attr.xml | 2 +- .../core/src/test/config/spring-start-nodes.xml | 2 +- .../grid/GridExternalizableAbstractTest.java | 2 +- .../grid/ggfs/GridGgfsPathSelfTest.java | 2 +- .../GridFailoverTaskWithPredicateSelfTest.java | 2 +- .../kernal/GridJobMasterLeaveAwareSelfTest.java | 2 +- .../grid/kernal/GridJobStealingSelfTest.java | 2 +- .../grid/kernal/GridLifecycleAwareSelfTest.java | 2 +- ...ectionLocalJobMultipleArgumentsSelfTest.java | 2 +- .../GridTaskExecutionContextSelfTest.java | 2 +- .../managers/GridManagerStopSelfTest.java | 2 +- .../cache/GridCacheAbstractSelfTest.java | 2 +- .../cache/GridCacheAffinityRoutingSelfTest.java | 2 +- .../cache/GridCacheDeploymentSelfTest.java | 2 +- .../cache/GridCacheEntryMemorySizeSelfTest.java | 2 +- .../cache/GridCacheMemoryModeSelfTest.java | 2 +- .../cache/GridCacheOffHeapSelfTest.java | 2 +- .../GridCacheReferenceCleanupSelfTest.java | 2 +- .../GridCacheAbstractJobExecutionTest.java | 2 +- .../GridCachePreloadLifecycleAbstractTest.java | 2 +- .../near/GridCacheNearEvictionSelfTest.java | 2 +- .../GridCacheSwapScanQueryAbstractSelfTest.java | 2 +- ...ridCacheContinuousQueryAbstractSelfTest.java | 2 +- ...dCacheAbstractReduceFieldsQuerySelfTest.java | 2 +- .../closure/GridClosureProcessorSelfTest.java | 2 +- .../continuous/GridEventConsumeSelfTest.java | 2 +- .../dataload/GridDataLoaderImplSelfTest.java | 2 +- .../GridDataLoaderProcessorSelfTest.java | 2 +- .../ggfs/GridGgfsFileInfoSelfTest.java | 2 +- .../streamer/GridStreamerEvictionSelfTest.java | 2 +- .../streamer/GridStreamerSelfTest.java | 2 +- .../marshaller/GridMarshallerAbstractTest.java | 2 +- .../GridMarshallerPerformanceTest.java | 2 +- .../GridOptimizedMarshallerEnumSelfTest.java | 1 + .../GridOptimizedMarshallerSelfTest.java | 1 + .../optimized/GridOptimizedMarshallerTest.java | 1 + .../GridOptimizedObjectStreamSelfTest.java | 1 + .../grid/messaging/GridMessagingSelfTest.java | 2 +- .../grid/spi/GridTcpSpiForwardingSelfTest.java | 2 +- ...GridTcpDiscoveryMarshallerCheckSelfTest.java | 2 +- .../util/future/GridFinishedFutureSelfTest.java | 2 +- .../testframework/junits/GridAbstractTest.java | 2 +- .../testframework/junits/GridTestResources.java | 2 +- .../core/src/test/webapp/META-INF/gg-config.xml | 2 +- .../child/GridHadoopExternalProcessStarter.java | 2 +- ...GridHadoopExternalCommunicationSelfTest.java | 2 +- .../GridCacheAbstractFieldsQuerySelfTest.java | 2 +- .../cache/GridCacheAbstractQuerySelfTest.java | 2 +- .../cache/GridCacheCrossCacheQuerySelfTest.java | 2 +- .../GridCacheQueryMultiThreadedSelfTest.java | 2 +- ...idCacheReduceQueryMultithreadedSelfTest.java | 2 +- .../processors/cache/GridCacheSwapSelfTest.java | 2 +- .../h2/opt/GridLuceneIndexLoadTest.java | 2 +- .../h2indexing/GridH2IndexingSpiLoadTest.java | 2 +- .../test/resources/spring-ping-pong-partner.xml | 2 +- .../GridSpringBeanSerializationSelfTest.java | 2 +- 108 files changed, 4603 insertions(+), 4609 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/examples/config/example-cache.xml ---------------------------------------------------------------------- diff --git a/examples/config/example-cache.xml b/examples/config/example-cache.xml index b9e95e2..f7024c0 100644 --- a/examples/config/example-cache.xml +++ b/examples/config/example-cache.xml @@ -36,7 +36,7 @@ <property name="peerClassLoadingEnabled" value="true"/> <property name="marshaller"> - <bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller"> + <bean class="org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller"> <!-- Set to false to allow non-serializable objects in examples, default is true. --> <property name="requireSerializable" value="false"/> </bean> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/examples/config/example-compute.xml ---------------------------------------------------------------------- diff --git a/examples/config/example-compute.xml b/examples/config/example-compute.xml index 6173a46..ffd6b04 100644 --- a/examples/config/example-compute.xml +++ b/examples/config/example-compute.xml @@ -30,7 +30,7 @@ <property name="peerClassLoadingEnabled" value="true"/> <property name="marshaller"> - <bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller"> + <bean class="org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller"> <!-- Set to false to allow non-serializable objects in examples, default is true. --> <property name="requireSerializable" value="false"/> </bean> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/examples/config/example-streamer.xml ---------------------------------------------------------------------- diff --git a/examples/config/example-streamer.xml b/examples/config/example-streamer.xml index eb86834..1c01e14 100644 --- a/examples/config/example-streamer.xml +++ b/examples/config/example-streamer.xml @@ -44,7 +44,7 @@ <property name="localHost" value="127.0.0.1"/> <property name="marshaller"> - <bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller"> + <bean class="org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller"> <!-- Set to false to allow non-serializable objects in examples, default is true. --> <property name="requireSerializable" value="false"/> </bean> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/examples/config/filesystem/example-ggfs.xml ---------------------------------------------------------------------- diff --git a/examples/config/filesystem/example-ggfs.xml b/examples/config/filesystem/example-ggfs.xml index a709b9a..c33c806 100644 --- a/examples/config/filesystem/example-ggfs.xml +++ b/examples/config/filesystem/example-ggfs.xml @@ -54,7 +54,7 @@ <property name="peerClassLoadingEnabled" value="true"/> <property name="marshaller"> - <bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller"> + <bean class="org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller"> <!-- Set to false to allow non-serializable objects in examples, default is true. --> <property name="requireSerializable" value="false"/> </bean> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/examples/src/main/java/org/gridgain/examples/misc/client/memcache/MemcacheRestExampleNodeStartup.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java/org/gridgain/examples/misc/client/memcache/MemcacheRestExampleNodeStartup.java b/examples/src/main/java/org/gridgain/examples/misc/client/memcache/MemcacheRestExampleNodeStartup.java index ac3842a..8322759 100644 --- a/examples/src/main/java/org/gridgain/examples/misc/client/memcache/MemcacheRestExampleNodeStartup.java +++ b/examples/src/main/java/org/gridgain/examples/misc/client/memcache/MemcacheRestExampleNodeStartup.java @@ -11,9 +11,9 @@ package org.gridgain.examples.misc.client.memcache; import org.apache.ignite.*; import org.apache.ignite.configuration.*; +import org.apache.ignite.marshaller.optimized.*; import org.gridgain.grid.*; import org.gridgain.grid.cache.*; -import org.gridgain.grid.marshaller.optimized.*; import org.gridgain.grid.spi.discovery.tcp.*; import org.gridgain.grid.spi.discovery.tcp.ipfinder.vm.*; import org.gridgain.grid.spi.indexing.h2.*; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/examples/src/main/java/org/gridgain/examples/misc/springbean/spring-bean.xml ---------------------------------------------------------------------- diff --git a/examples/src/main/java/org/gridgain/examples/misc/springbean/spring-bean.xml b/examples/src/main/java/org/gridgain/examples/misc/springbean/spring-bean.xml index eba9308..23c562e 100644 --- a/examples/src/main/java/org/gridgain/examples/misc/springbean/spring-bean.xml +++ b/examples/src/main/java/org/gridgain/examples/misc/springbean/spring-bean.xml @@ -33,7 +33,7 @@ <property name="peerClassLoadingEnabled" value="true"/> <property name="marshaller"> - <bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller"> + <bean class="org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller"> <!-- Set to false to allow non-serializable objects in examples, default is true. --> <property name="requireSerializable" value="false"/> </bean> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/aop/src/test/java/org/gridgain/grid/marshaller/optimized/GridOptimizedMarshallerAopTest.java ---------------------------------------------------------------------- diff --git a/modules/aop/src/test/java/org/gridgain/grid/marshaller/optimized/GridOptimizedMarshallerAopTest.java b/modules/aop/src/test/java/org/gridgain/grid/marshaller/optimized/GridOptimizedMarshallerAopTest.java index e63a929..80c596f 100644 --- a/modules/aop/src/test/java/org/gridgain/grid/marshaller/optimized/GridOptimizedMarshallerAopTest.java +++ b/modules/aop/src/test/java/org/gridgain/grid/marshaller/optimized/GridOptimizedMarshallerAopTest.java @@ -13,6 +13,7 @@ import org.apache.ignite.compute.gridify.*; import org.apache.ignite.configuration.*; import org.apache.ignite.events.*; import org.apache.ignite.lang.*; +import org.apache.ignite.marshaller.optimized.*; import org.gridgain.grid.util.typedef.*; import org.gridgain.testframework.junits.common.*; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/IgniteCompute.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCompute.java b/modules/core/src/main/java/org/apache/ignite/IgniteCompute.java index 01d3800..4ea1d8a 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteCompute.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteCompute.java @@ -13,7 +13,6 @@ import org.apache.ignite.cluster.*; import org.apache.ignite.compute.*; import org.apache.ignite.lang.*; import org.gridgain.grid.*; -import org.gridgain.grid.marshaller.optimized.*; import org.gridgain.grid.spi.failover.*; import org.gridgain.grid.spi.loadbalancing.*; import org.jetbrains.annotations.*; @@ -47,7 +46,7 @@ import java.util.concurrent.*; * not have any alive nodes), then {@link GridEmptyProjectionException} will be thrown out of result future. * <h1 class="header">Serializable</h1> * Also note that {@link Runnable} and {@link Callable} implementations must support serialization as required - * by the configured marshaller. For example, {@link GridOptimizedMarshaller} requires {@link Serializable} + * by the configured marshaller. For example, {@link org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller} requires {@link Serializable} * objects by default, but can be configured not to. Generally speaking objects that implement {@link Serializable} * or {@link Externalizable} will perform better. For {@link Runnable} and {@link Callable} interfaces * GridGain provides analogous {@link org.apache.ignite.lang.IgniteRunnable} and {@link org.apache.ignite.lang.IgniteCallable} classes which are http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java index d7dc2c1..2254ffb 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java @@ -25,7 +25,6 @@ import org.gridgain.grid.dr.hub.sender.*; import org.gridgain.grid.ggfs.*; import org.gridgain.grid.hadoop.*; import org.gridgain.grid.kernal.managers.eventstorage.*; -import org.gridgain.grid.marshaller.optimized.*; import org.gridgain.grid.portables.*; import org.gridgain.grid.security.*; import org.gridgain.grid.segmentation.*; @@ -1455,7 +1454,7 @@ public class IgniteConfiguration { /** * Should return an instance of marshaller to use in grid. If not provided, - * {@link GridOptimizedMarshaller} will be used on Java HotSpot VM, and + * {@link org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller} will be used on Java HotSpot VM, and * {@link org.apache.ignite.marshaller.jdk.GridJdkMarshaller} will be used on other VMs. * * @return Marshaller to use in grid. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/lang/IgniteUuid.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/lang/IgniteUuid.java b/modules/core/src/main/java/org/apache/ignite/lang/IgniteUuid.java index 604ad36..5f02da9 100644 --- a/modules/core/src/main/java/org/apache/ignite/lang/IgniteUuid.java +++ b/modules/core/src/main/java/org/apache/ignite/lang/IgniteUuid.java @@ -9,7 +9,7 @@ package org.apache.ignite.lang; -import org.gridgain.grid.marshaller.optimized.*; +import org.apache.ignite.marshaller.optimized.*; import org.gridgain.grid.util.typedef.*; import org.gridgain.grid.util.typedef.internal.*; import org.gridgain.grid.util.lang.*; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/GridMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/GridMarshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/GridMarshaller.java index 9c8685f..d0b8826 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/GridMarshaller.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/GridMarshaller.java @@ -10,7 +10,6 @@ package org.apache.ignite.marshaller; import org.gridgain.grid.*; -import org.gridgain.grid.marshaller.optimized.*; import org.jetbrains.annotations.*; import java.io.*; @@ -22,7 +21,7 @@ import java.io.*; * <p> * Gridgain provides the following {@code GridMarshaller} implementations: * <ul> - * <li>{@link GridOptimizedMarshaller} - default</li> + * <li>{@link org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller} - default</li> * <li>{@link org.apache.ignite.marshaller.jdk.GridJdkMarshaller}</li> * </ul> * <p> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/GridJdkMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/GridJdkMarshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/GridJdkMarshaller.java index da75a2e..d0c3246 100644 --- a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/GridJdkMarshaller.java +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/GridJdkMarshaller.java @@ -11,7 +11,6 @@ package org.apache.ignite.marshaller.jdk; import org.apache.ignite.marshaller.*; import org.gridgain.grid.*; -import org.gridgain.grid.marshaller.optimized.*; import org.gridgain.grid.util.typedef.internal.*; import org.jetbrains.annotations.*; @@ -24,7 +23,7 @@ import java.io.*; * <h2 class="header">Mandatory</h2> * This marshaller has no mandatory configuration parameters. * <h2 class="header">Java Example</h2> - * {@code GridJdkMarshaller} needs to be explicitly configured to override default {@link GridOptimizedMarshaller}. + * {@code GridJdkMarshaller} needs to be explicitly configured to override default {@link org.apache.ignite.marshaller.optimized.GridOptimizedMarshaller}. * <pre name="code" class="java"> * GridJdkMarshaller marshaller = new GridJdkMarshaller(); * http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassDescriptor.java new file mode 100644 index 0000000..6384e3b --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassDescriptor.java @@ -0,0 +1,1032 @@ +/* @java.file.header */ + +/* _________ _____ __________________ _____ + * __ ____/___________(_)______ /__ ____/______ ____(_)_______ + * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \ + * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / / + * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/ + */ + +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.lang.*; +import org.apache.ignite.marshaller.*; +import org.gridgain.grid.util.*; +import org.gridgain.grid.util.typedef.*; +import sun.misc.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import static java.lang.reflect.Modifier.*; + +/** + * Class descriptor. + */ +class GridOptimizedClassDescriptor { + /** Unsafe. */ + private static final Unsafe UNSAFE = GridUnsafe.unsafe(); + + /** */ + private static final int TYPE_BYTE = 1; + + /** */ + private static final int TYPE_SHORT = 2; + + /** */ + private static final int TYPE_INT = 3; + + /** */ + private static final int TYPE_LONG = 4; + + /** */ + private static final int TYPE_FLOAT = 5; + + /** */ + private static final int TYPE_DOUBLE = 6; + + /** */ + private static final int TYPE_CHAR = 7; + + /** */ + private static final int TYPE_BOOLEAN = 8; + + /** */ + private static final int TYPE_BYTE_ARR = 9; + + /** */ + private static final int TYPE_SHORT_ARR = 10; + + /** */ + private static final int TYPE_INT_ARR = 11; + + /** */ + private static final int TYPE_LONG_ARR = 12; + + /** */ + private static final int TYPE_FLOAT_ARR = 13; + + /** */ + private static final int TYPE_DOUBLE_ARR = 14; + + /** */ + private static final int TYPE_CHAR_ARR = 15; + + /** */ + private static final int TYPE_BOOLEAN_ARR = 16; + + /** */ + private static final int TYPE_OBJ_ARR = 17; + + /** */ + private static final int TYPE_STR = 18; + + /** */ + private static final int TYPE_ENUM = 19; + + /** */ + private static final int TYPE_UUID = 20; + + /** */ + private static final int TYPE_PROPS = 21; + + /** */ + private static final int TYPE_ARRAY_LIST = 22; + + /** */ + private static final int TYPE_HASH_MAP = 23; + + /** */ + private static final int TYPE_HASH_SET = 24; + + /** */ + private static final int TYPE_LINKED_LIST = 25; + + /** */ + private static final int TYPE_LINKED_HASH_MAP = 26; + + /** */ + private static final int TYPE_LINKED_HASH_SET = 27; + + /** */ + private static final int TYPE_DATE = 28; + + /** */ + private static final int TYPE_CLS = 29; + + /** */ + private static final int TYPE_EXTERNALIZABLE = 50; + + /** */ + private static final int TYPE_SERIALIZABLE = 51; + + /** Class. */ + private Class<?> cls; + + /** Header. */ + private Integer hdr; + + /** ID. */ + private Integer id; + + /** Short ID. */ + private Short shortId; + + /** Class name. */ + private String name; + + /** Class type. */ + private int type; + + /** Primitive flag. */ + private boolean isPrimitive; + + /** Enum flag. */ + private boolean isEnum; + + /** Serializable flag. */ + private boolean isSerial; + + /** Excluded flag. */ + private final boolean excluded; + + /** {@code True} if descriptor is for {@link Class}. */ + private boolean isCls; + + /** Array component type. */ + private Class<?> arrCompType; + + /** Enumeration values. */ + private Object[] enumVals; + + /** Constructor. */ + private Constructor<?> constructor; + + /** Fields. */ + private Fields fields; + + /** {@code writeObject} methods. */ + private List<Method> writeObjMtds; + + /** {@code writeReplace} method. */ + private Method writeReplaceMtd; + + /** {@code readObject} methods. */ + private List<Method> readObjMtds; + + /** {@code readResolve} method. */ + private Method readResolveMtd; + + /** Defaults field offset. */ + private long dfltsFieldOff; + + /** Load factor field offset. */ + private long loadFactorFieldOff; + + /** Map field offset. */ + private long mapFieldOff; + + /** Access order field offset. */ + private long accessOrderFieldOff; + + /** + * Creates descriptor for class. + * + * @param cls Class. + * @throws IOException In case of error. + */ + @SuppressWarnings({"ForLoopReplaceableByForEach", "MapReplaceableByEnumMap"}) + GridOptimizedClassDescriptor(Class<?> cls) throws IOException { + this.cls = cls; + + excluded = GridMarshallerExclusions.isExcluded(cls); + + T2<Integer, Integer> t = GridOptimizedClassResolver.writeClassData(cls); + + hdr = t.get1(); + id = t.get2(); + name = cls.getName(); + + if (!excluded) { + Class<?> parent; + + if (cls == byte.class || cls == Byte.class) { + type = TYPE_BYTE; + + isPrimitive = true; + } + else if (cls == short.class || cls == Short.class) { + type = TYPE_SHORT; + + isPrimitive = true; + } + else if (cls == int.class || cls == Integer.class) { + type = TYPE_INT; + + isPrimitive = true; + } + else if (cls == long.class || cls == Long.class) { + type = TYPE_LONG; + + isPrimitive = true; + } + else if (cls == float.class || cls == Float.class) { + type = TYPE_FLOAT; + + isPrimitive = true; + } + else if (cls == double.class || cls == Double.class) { + type = TYPE_DOUBLE; + + isPrimitive = true; + } + else if (cls == char.class || cls == Character.class) { + type = TYPE_CHAR; + + isPrimitive = true; + } + else if (cls == boolean.class || cls == Boolean.class) { + type = TYPE_BOOLEAN; + + isPrimitive = true; + } + else if (cls == byte[].class) + type = TYPE_BYTE_ARR; + else if (cls == short[].class) + type = TYPE_SHORT_ARR; + else if (cls == int[].class) + type = TYPE_INT_ARR; + else if (cls == long[].class) + type = TYPE_LONG_ARR; + else if (cls == float[].class) + type = TYPE_FLOAT_ARR; + else if (cls == double[].class) + type = TYPE_DOUBLE_ARR; + else if (cls == char[].class) + type = TYPE_CHAR_ARR; + else if (cls == boolean[].class) + type = TYPE_BOOLEAN_ARR; + else if (cls.isArray()) { + type = TYPE_OBJ_ARR; + + arrCompType = cls.getComponentType(); + } + else if (cls == String.class) + type = TYPE_STR; + else if (cls.isEnum()) { + type = TYPE_ENUM; + + isEnum = true; + enumVals = cls.getEnumConstants(); + } + // Support for enum constants, based on anonymous children classes. + else if ((parent = cls.getSuperclass()) != null && parent.isEnum()) { + type = TYPE_ENUM; + + isEnum = true; + enumVals = parent.getEnumConstants(); + } + else if (cls == UUID.class) + type = TYPE_UUID; + else if (cls == Properties.class) { + type = TYPE_PROPS; + + try { + dfltsFieldOff = UNSAFE.objectFieldOffset(Properties.class.getDeclaredField("defaults")); + } + catch (NoSuchFieldException e) { + throw new IOException(e); + } + } + else if (cls == ArrayList.class) + type = TYPE_ARRAY_LIST; + else if (cls == HashMap.class) { + type = TYPE_HASH_MAP; + + try { + loadFactorFieldOff = UNSAFE.objectFieldOffset(HashMap.class.getDeclaredField("loadFactor")); + } + catch (NoSuchFieldException e) { + throw new IOException(e); + } + } + else if (cls == HashSet.class) { + type = TYPE_HASH_SET; + + try { + loadFactorFieldOff = UNSAFE.objectFieldOffset(HashMap.class.getDeclaredField("loadFactor")); + mapFieldOff = UNSAFE.objectFieldOffset(HashSet.class.getDeclaredField("map")); + } + catch (NoSuchFieldException e) { + throw new IOException(e); + } + } + else if (cls == LinkedList.class) + type = TYPE_LINKED_LIST; + else if (cls == LinkedHashMap.class) { + type = TYPE_LINKED_HASH_MAP; + + try { + loadFactorFieldOff = UNSAFE.objectFieldOffset(HashMap.class.getDeclaredField("loadFactor")); + accessOrderFieldOff = UNSAFE.objectFieldOffset(LinkedHashMap.class.getDeclaredField("accessOrder")); + } + catch (NoSuchFieldException e) { + throw new IOException(e); + } + } + else if (cls == LinkedHashSet.class) { + type = TYPE_LINKED_HASH_SET; + + try { + loadFactorFieldOff = UNSAFE.objectFieldOffset(HashMap.class.getDeclaredField("loadFactor")); + mapFieldOff = UNSAFE.objectFieldOffset(HashSet.class.getDeclaredField("map")); + } + catch (NoSuchFieldException e) { + throw new IOException(e); + } + } + else if (cls == Date.class) + type = TYPE_DATE; + else if (cls == Class.class) { + type = TYPE_CLS; + + isCls = true; + } + else { + Class<?> c = cls; + + while ((writeReplaceMtd == null || readResolveMtd == null) && c != null && !c.equals(Object.class)) { + if (writeReplaceMtd == null) { + try { + writeReplaceMtd = c.getDeclaredMethod("writeReplace"); + + if (!isStatic(writeReplaceMtd.getModifiers()) && + !(isPrivate(writeReplaceMtd.getModifiers()) && c != cls) && + writeReplaceMtd.getReturnType().equals(Object.class)) + writeReplaceMtd.setAccessible(true); + else + // Set method back to null if it has incorrect signature. + writeReplaceMtd = null; + } + catch (NoSuchMethodException ignored) { + // No-op. + } + } + + if (readResolveMtd == null) { + try { + readResolveMtd = c.getDeclaredMethod("readResolve"); + + if (!isStatic(readResolveMtd.getModifiers()) && + !(isPrivate(readResolveMtd.getModifiers()) && c != cls) && + readResolveMtd.getReturnType().equals(Object.class)) + readResolveMtd.setAccessible(true); + else + // Set method back to null if it has incorrect signature. + readResolveMtd = null; + } + catch (NoSuchMethodException ignored) { + // No-op. + } + } + + c = c.getSuperclass(); + } + + if (Externalizable.class.isAssignableFrom(cls)) { + type = TYPE_EXTERNALIZABLE; + + try { + constructor = cls.getDeclaredConstructor(); + + constructor.setAccessible(true); + } + catch (NoSuchMethodException e) { + throw new IOException("Externalizable class doesn't have default constructor: " + cls, e); + } + } + else { + type = TYPE_SERIALIZABLE; + + isSerial = Serializable.class.isAssignableFrom(cls); + + writeObjMtds = new ArrayList<>(); + readObjMtds = new ArrayList<>(); + List<List<Field>> fields = new ArrayList<>(); + List<List<T2<GridOptimizedFieldType, Long>>> fieldOffs = new ArrayList<>(); + List<Map<String, IgniteBiTuple<Integer, GridOptimizedFieldType>>> fieldInfoMaps = new ArrayList<>(); + List<List<IgniteBiTuple<Integer, GridOptimizedFieldType>>> fieldInfoLists = new ArrayList<>(); + + for (c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { + Method mtd; + + try { + mtd = c.getDeclaredMethod("writeObject", ObjectOutputStream.class); + + int mod = mtd.getModifiers(); + + if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE) + mtd.setAccessible(true); + else + // Set method back to null if it has incorrect signature. + mtd = null; + } + catch (NoSuchMethodException ignored) { + mtd = null; + } + + writeObjMtds.add(mtd); + + try { + mtd = c.getDeclaredMethod("readObject", ObjectInputStream.class); + + int mod = mtd.getModifiers(); + + if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE) + mtd.setAccessible(true); + else + // Set method back to null if it has incorrect signature. + mtd = null; + } + catch (NoSuchMethodException ignored) { + mtd = null; + } + + readObjMtds.add(mtd); + + Field[] clsFields0 = c.getDeclaredFields(); + + Arrays.sort(clsFields0, new Comparator<Field>() { + @Override public int compare(Field f1, Field f2) { + return f1.getName().compareTo(f2.getName()); + } + }); + + List<Field> clsFields = new ArrayList<>(clsFields0.length); + List<T2<GridOptimizedFieldType, Long>> clsFieldOffs = + new ArrayList<>(clsFields0.length); + + for (int i = 0; i < clsFields0.length; i++) { + Field f = clsFields0[i]; + + int mod = f.getModifiers(); + + if (!isStatic(mod) && !isTransient(mod)) { + GridOptimizedFieldType type = fieldType(f.getType()); + + clsFields.add(f); + clsFieldOffs.add(new T2<>(type, UNSAFE.objectFieldOffset(f))); + } + } + + fields.add(clsFields); + fieldOffs.add(clsFieldOffs); + + Map<String, IgniteBiTuple<Integer, GridOptimizedFieldType>> fieldInfoMap = null; + + try { + Field serFieldsDesc = c.getDeclaredField("serialPersistentFields"); + + int mod = serFieldsDesc.getModifiers(); + + if (serFieldsDesc.getType() == ObjectStreamField[].class && + isPrivate(mod) && isStatic(mod) && isFinal(mod)) { + serFieldsDesc.setAccessible(true); + + ObjectStreamField[] serFields = (ObjectStreamField[])serFieldsDesc.get(null); + + fieldInfoMap = new HashMap<>(); + + for (int i = 0; i < serFields.length; i++) { + ObjectStreamField serField = serFields[i]; + + fieldInfoMap.put(serField.getName(), F.t(i, fieldType(serField.getType()))); + } + } + } + catch (NoSuchFieldException ignored) { + // No-op. + } + catch (IllegalAccessException e) { + throw new IOException("Failed to get value of 'serialPersistentFields' field in class: " + + cls.getName(), e); + } + + if (fieldInfoMap == null) { + fieldInfoMap = new HashMap<>(); + + for (int i = 0; i < clsFields.size(); i++) { + Field f = clsFields.get(i); + + fieldInfoMap.put(f.getName(), F.t(i, fieldType(f.getType()))); + } + } + + fieldInfoMaps.add(fieldInfoMap); + + List<IgniteBiTuple<Integer, GridOptimizedFieldType>> fieldInfoList = + new ArrayList<>(fieldInfoMap.values()); + + Collections.sort(fieldInfoList, new Comparator<IgniteBiTuple<Integer, GridOptimizedFieldType>>() { + @Override public int compare(IgniteBiTuple<Integer, GridOptimizedFieldType> t1, + IgniteBiTuple<Integer, GridOptimizedFieldType> t2) { + return t1.get1().compareTo(t2.get1()); + } + }); + + fieldInfoLists.add(fieldInfoList); + } + + Collections.reverse(writeObjMtds); + Collections.reverse(readObjMtds); + Collections.reverse(fields); + Collections.reverse(fieldOffs); + Collections.reverse(fieldInfoMaps); + Collections.reverse(fieldInfoLists); + + this.fields = new Fields(fields, fieldOffs, fieldInfoLists, fieldInfoMaps); + } + } + } + + shortId = GridOptimizedMarshallerUtils.computeSerialVersionUid(cls, fields != null ? fields.ownFields() : null).shortValue(); + } + + /** + * @return Excluded flag. + */ + boolean excluded() { + return excluded; + } + + /** + * @return Class. + */ + Class<?> describedClass() { + return cls; + } + + /** + * @return Header. + */ + Integer header() { + return hdr; + } + + /** + * @return ID. + */ + Integer id() { + return id; + } + + /** + * @return Short ID. + */ + Short shortId() { + return shortId; + } + + /** + * @return Class name. + */ + String name() { + return name; + } + + /** + * @return Array component type. + */ + Class<?> componentType() { + return arrCompType; + } + + /** + * @return Primitive flag. + */ + boolean isPrimitive() { + return isPrimitive; + } + + /** + * @return Enum flag. + */ + boolean isEnum() { + return isEnum; + } + + /** + * @return {@code True} if descriptor is for {@link Class}. + */ + boolean isClass() { + return isCls; + } + + /** + * Replaces object. + * + * @param obj Object. + * @return Replaced object or {@code null} if there is no {@code writeReplace} method. + * @throws IOException In case of error. + */ + Object replace(Object obj) throws IOException { + if (writeReplaceMtd != null) { + try { + return writeReplaceMtd.invoke(obj); + } + catch (IllegalAccessException | InvocationTargetException e) { + throw new IOException(e); + } + } + + return obj; + } + + /** + * Writes object to stream. + * + * @param out Output stream. + * @param obj Object. + * @throws IOException In case of error. + */ + @SuppressWarnings("ForLoopReplaceableByForEach") + void write(GridOptimizedObjectOutputStream out, Object obj) throws IOException { + switch (type) { + case TYPE_BYTE: + out.writeByte((Byte)obj); + + break; + + case TYPE_SHORT: + out.writeShort((Short)obj); + + break; + + case TYPE_INT: + out.writeInt((Integer)obj); + + break; + + case TYPE_LONG: + out.writeLong((Long)obj); + + break; + + case TYPE_FLOAT: + out.writeFloat((Float)obj); + + break; + + case TYPE_DOUBLE: + out.writeDouble((Double)obj); + + break; + + case TYPE_CHAR: + out.writeChar((Character)obj); + + break; + + case TYPE_BOOLEAN: + out.writeBoolean((Boolean)obj); + + break; + + case TYPE_BYTE_ARR: + out.writeByteArray((byte[])obj); + + break; + + case TYPE_SHORT_ARR: + out.writeShortArray((short[])obj); + + break; + + case TYPE_INT_ARR: + out.writeIntArray((int[])obj); + + break; + + case TYPE_LONG_ARR: + out.writeLongArray((long[])obj); + + break; + + case TYPE_FLOAT_ARR: + out.writeFloatArray((float[])obj); + + break; + + case TYPE_DOUBLE_ARR: + out.writeDoubleArray((double[])obj); + + break; + + case TYPE_CHAR_ARR: + out.writeCharArray((char[])obj); + + break; + + case TYPE_BOOLEAN_ARR: + out.writeBooleanArray((boolean[])obj); + + break; + + case TYPE_OBJ_ARR: + out.writeArray((Object[])obj); + + break; + + case TYPE_STR: + out.writeString((String)obj); + + break; + + case TYPE_ENUM: + out.writeInt(((Enum)obj).ordinal()); + + break; + + case TYPE_UUID: + out.writeUuid((UUID)obj); + + break; + + case TYPE_PROPS: + out.writeProperties((Properties)obj, dfltsFieldOff); + + break; + + case TYPE_ARRAY_LIST: + out.writeArrayList((ArrayList<?>)obj); + + break; + + case TYPE_HASH_MAP: + out.writeHashMap((HashMap<?, ?>)obj, loadFactorFieldOff, false); + + break; + + case TYPE_HASH_SET: + out.writeHashSet((HashSet<?>)obj, mapFieldOff, loadFactorFieldOff); + + break; + + case TYPE_LINKED_LIST: + out.writeLinkedList((LinkedList<?>)obj); + + break; + + case TYPE_LINKED_HASH_MAP: + out.writeLinkedHashMap((LinkedHashMap<?, ?>)obj, loadFactorFieldOff, accessOrderFieldOff, false); + + break; + + case TYPE_LINKED_HASH_SET: + out.writeLinkedHashSet((LinkedHashSet<?>)obj, mapFieldOff, loadFactorFieldOff); + + break; + + case TYPE_DATE: + out.writeDate((Date)obj); + + break; + + case TYPE_CLS: + GridOptimizedClassResolver.writeClass(out, GridOptimizedMarshallerUtils.classDescriptor((Class<?>) obj, obj)); + + break; + + case TYPE_EXTERNALIZABLE: + out.writeExternalizable(obj); + + break; + + case TYPE_SERIALIZABLE: + if (out.requireSerializable() && !isSerial) + throw new NotSerializableException("Must implement java.io.Serializable or " + + "set GridOptimizedMarshaller.setRequireSerializable() to false " + + "(note that performance may degrade if object is not Serializable): " + name); + + out.writeSerializable(obj, writeObjMtds, fields); + + break; + + default: + throw new IllegalStateException("Invalid class type: " + type); + } + } + + /** + * Reads object from stream. + * + * @param in Input stream. + * @return Object. + * @throws ClassNotFoundException If class not found. + * @throws IOException In case of error. + */ + Object read(GridOptimizedObjectInputStream in) throws ClassNotFoundException, IOException { + switch (type) { + case TYPE_BYTE: + return in.readByte(); + + case TYPE_SHORT: + return in.readShort(); + + case TYPE_INT: + return in.readInt(); + + case TYPE_LONG: + return in.readLong(); + + case TYPE_FLOAT: + return in.readFloat(); + + case TYPE_DOUBLE: + return in.readDouble(); + + case TYPE_CHAR: + return in.readChar(); + + case TYPE_BOOLEAN: + return in.readBoolean(); + + case TYPE_BYTE_ARR: + return in.readByteArray(); + + case TYPE_SHORT_ARR: + return in.readShortArray(); + + case TYPE_INT_ARR: + return in.readIntArray(); + + case TYPE_LONG_ARR: + return in.readLongArray(); + + case TYPE_FLOAT_ARR: + return in.readFloatArray(); + + case TYPE_DOUBLE_ARR: + return in.readDoubleArray(); + + case TYPE_CHAR_ARR: + return in.readCharArray(); + + case TYPE_BOOLEAN_ARR: + return in.readBooleanArray(); + + case TYPE_OBJ_ARR: + return in.readArray(arrCompType); + + case TYPE_STR: + return in.readString(); + + case TYPE_ENUM: + return enumVals[in.readInt()]; + + case TYPE_UUID: + return in.readUuid(); + + case TYPE_PROPS: + return in.readProperties(); + + case TYPE_ARRAY_LIST: + return in.readArrayList(); + + case TYPE_HASH_MAP: + return in.readHashMap(false); + + case TYPE_HASH_SET: + return in.readHashSet(mapFieldOff); + + case TYPE_LINKED_LIST: + return in.readLinkedList(); + + case TYPE_LINKED_HASH_MAP: + return in.readLinkedHashMap(false); + + case TYPE_LINKED_HASH_SET: + return in.readLinkedHashSet(mapFieldOff); + + case TYPE_DATE: + return in.readDate(); + + case TYPE_CLS: + return GridOptimizedClassResolver.readClass(in, in.classLoader()).describedClass(); + + case TYPE_EXTERNALIZABLE: + return in.readExternalizable(constructor, readResolveMtd); + + case TYPE_SERIALIZABLE: + return in.readSerializable(cls, readObjMtds, readResolveMtd, fields); + + default: + throw new IllegalStateException("Invalid class type: " + type); + } + } + + /** + * @param cls Class. + * @return Type. + */ + @SuppressWarnings("IfMayBeConditional") + private GridOptimizedFieldType fieldType(Class<?> cls) { + GridOptimizedFieldType type; + + if (cls == byte.class) + type = GridOptimizedFieldType.BYTE; + else if (cls == short.class) + type = GridOptimizedFieldType.SHORT; + else if (cls == int.class) + type = GridOptimizedFieldType.INT; + else if (cls == long.class) + type = GridOptimizedFieldType.LONG; + else if (cls == float.class) + type = GridOptimizedFieldType.FLOAT; + else if (cls == double.class) + type = GridOptimizedFieldType.DOUBLE; + else if (cls == char.class) + type = GridOptimizedFieldType.CHAR; + else if (cls == boolean.class) + type = GridOptimizedFieldType.BOOLEAN; + else + type = GridOptimizedFieldType.OTHER; + + return type; + } + + /** + * Encapsulates data about class fields. + */ + @SuppressWarnings("PackageVisibleInnerClass") + static class Fields { + /** Fields. */ + private final List<List<Field>> fields; + + /** Fields offsets. */ + private final List<List<T2<GridOptimizedFieldType, Long>>> fieldOffs; + + /** Fields details lists. */ + private final List<List<IgniteBiTuple<Integer, GridOptimizedFieldType>>> fieldInfoLists; + + /** Fields details maps. */ + private final List<Map<String, IgniteBiTuple<Integer, GridOptimizedFieldType>>> fieldInfoMaps; + + /** + * Creates new instance. + * + * @param fields Fields. + * @param fieldOffs Field offsets. + * @param fieldInfoLists List of field details sequences for each type in the object's class hierarchy. + * @param fieldInfoMaps List of field details maps for each type in the object's class hierarchy. + */ + Fields(List<List<Field>> fields, List<List<T2<GridOptimizedFieldType, Long>>> fieldOffs, + List<List<IgniteBiTuple<Integer, GridOptimizedFieldType>>> fieldInfoLists, + List<Map<String, IgniteBiTuple<Integer, GridOptimizedFieldType>>> fieldInfoMaps) { + this.fields = fields; + this.fieldOffs = fieldOffs; + this.fieldInfoLists = fieldInfoLists; + this.fieldInfoMaps = fieldInfoMaps; + } + + /** + * Returns class's own fields (excluding inherited). + * + * @return List of fields or {@code null} if fields list is empty. + */ + List<Field> ownFields() { + return fields.isEmpty() ? null : fields.get(fields.size() - 1); + } + + /** + * Returns field types and their offsets. + * + * @param i hierarchy level where 0 corresponds to top level. + * @return list of pairs where first value is field type and second value is its offset. + */ + List<T2<GridOptimizedFieldType, Long>> fieldOffs(int i) { + return fieldOffs.get(i); + } + + /** + * Returns field sequence numbers and their types as list. + * + * @param i hierarchy level where 0 corresponds to top level. + * @return list of pairs (field number, field type) for the given hierarchy level. + */ + List<IgniteBiTuple<Integer, GridOptimizedFieldType>> fieldInfoList(int i) { + return fieldInfoLists.get(i); + } + + /** + * Returns field sequence numbers and their types as map where key is a field name, + * + * @param i hierarchy level where 0 corresponds to top level. + * @return map of field names and their details. + */ + Map<String, IgniteBiTuple<Integer, GridOptimizedFieldType>> fieldInfoMap(int i) { + return fieldInfoMaps.get(i); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassResolver.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassResolver.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassResolver.java new file mode 100644 index 0000000..7b21ebe --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedClassResolver.java @@ -0,0 +1,469 @@ +/* @java.file.header */ + +/* _________ _____ __________________ _____ + * __ ____/___________(_)______ /__ ____/______ ____(_)_______ + * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \ + * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / / + * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/ + */ + +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.lang.*; +import org.gridgain.grid.util.*; +import org.gridgain.grid.util.typedef.*; +import org.gridgain.grid.util.typedef.internal.*; +import org.jdk8.backport.*; +import org.jetbrains.annotations.*; + +import java.io.*; +import java.math.*; +import java.sql.*; +import java.util.*; +import java.util.Date; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.*; + +/** + * Resolves class names by serialVersionUID. + */ +@SuppressWarnings({"UnnecessaryFullyQualifiedName", "unchecked"}) +class GridOptimizedClassResolver { + /** File name to generate. */ + private static final String FILE_NAME = "optimized-classnames.properties"; + + /** */ + private static final Map<String, Integer> ggxName2id = new HashMap<>(); + + /** */ + private static final T2<Class<?>, GridOptimizedClassDescriptor>[] ggxId2name; + + /** */ + private static final Map<String, Integer> ggName2id = new HashMap<>(); + + /** */ + private static final T3<String, Class<?>, GridOptimizedClassDescriptor>[] ggId2name; + + /** */ + private static Map<String, Integer> usrName2Id; + + /** */ + private static T3<String, Class<?>, GridOptimizedClassDescriptor>[] usrId2Name; + + /** */ + private static final int HEADER_NAME = 255; + + /** */ + private static final int HEADER_GG_NAME = 254; + + /** */ + private static final int HEADER_USER_NAME = 253; + + /** */ + private static final int HEADER_ARRAY = 252; + + /** + * Initialize predefined classes to optimize. + */ + static { + Class[] superOptCls = new Class[] { + // Array types. + byte[].class, + short[].class, + int[].class, + long[].class, + float[].class, + double[].class, + boolean[].class, + char[].class, + + // Boxed types. + Byte.class, + Short.class, + Integer.class, + Long.class, + Float.class, + Double.class, + Boolean.class, + Character.class, + String.class, + + // Atomic. + AtomicBoolean.class,AtomicInteger.class, + AtomicLong.class,AtomicReference.class, + AtomicMarkableReference.class, + AtomicStampedReference.class, + AtomicIntegerArray.class, + AtomicReferenceArray.class, + + // Concurrent types. + ConcurrentHashMap.class, + ConcurrentLinkedQueue.class, + ConcurrentSkipListMap.class, + ConcurrentSkipListSet.class, + LinkedBlockingDeque.class, + LinkedBlockingQueue.class, + PriorityBlockingQueue.class, + CopyOnWriteArrayList.class, + CopyOnWriteArraySet.class, + + // Locks. + ReentrantLock.class, + ReentrantReadWriteLock.class, + ReentrantReadWriteLock.ReadLock.class, + ReentrantReadWriteLock.WriteLock.class, + + // Util types. + Date.class, + UUID.class, + Calendar.class, + Random.class, + Calendar.class, + Currency.class, + ArrayList.class, + LinkedList.class, + Stack.class, + Vector.class, + HashMap.class, + HashSet.class, + Hashtable.class, + TreeMap.class, + TreeSet.class, + IdentityHashMap.class, + LinkedHashMap.class, + LinkedHashSet.class, + ArrayDeque.class, + BitSet.class, + EnumMap.class, + EnumSet.class, + + // SQL types. + java.sql.Date.class, + Time.class, + Timestamp.class, + + // Math types. + BigDecimal.class, + BigInteger.class, + + // GridGain types. + IgniteUuid.class, + GridBoundedConcurrentOrderedSet.class, + GridBoundedLinkedHashSet.class, + GridConcurrentHashSet.class, + ConcurrentLinkedDeque8.class, + GridConcurrentPhantomHashSet.class, + GridConcurrentSkipListSet.class, + GridConcurrentWeakHashSet.class, + GridIdentityHashSet.class, + GridLeanSet.class, + GridSetWrapper.class + }; + + // Have to leave a range for special purposes. + assert superOptCls.length < 230; + + ggxId2name = new T2[superOptCls.length]; + + for (int i = 0; i < superOptCls.length; i++) { + Class cls = superOptCls[i]; + + ggxName2id.put(cls.getName(), i); + ggxId2name[i] = new T2<Class<?>, GridOptimizedClassDescriptor>(cls, null); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader( + GridOptimizedClassResolver.class.getResourceAsStream(FILE_NAME), + GridOptimizedMarshallerUtils.UTF_8)); + + List<T3<String, Class<?>, GridOptimizedClassDescriptor>> ggId2name0 = + new LinkedList<>(); + + try { + for (int i = 0; ; i++) { + String clsName = reader.readLine(); + + if (clsName == null) + break; + + ggName2id.put(clsName, i); + ggId2name0.add(new T3<String, Class<?>, GridOptimizedClassDescriptor>(clsName, null, null)); + } + + ggId2name = ggId2name0.toArray(new T3[ggId2name0.size()]); + } + catch (IOException e) { + throw new AssertionError(e); + } + finally { + U.close(reader, null); + } + } + + /** + * Ensure singleton. + */ + private GridOptimizedClassResolver() { + // No-op. + } + + /** + * @param usrName2id0 From name to ID. + * @param usrId2Name0 From ID to name. + */ + static void userClasses(@Nullable Map<String, Integer> usrName2id0, + @Nullable T3<String, Class<?>, GridOptimizedClassDescriptor>[] usrId2Name0) { + usrName2Id = usrName2id0; + usrId2Name = usrId2Name0; + } + + /** + * @param in DataInput to read from. + * @param clsLdr ClassLoader. + * @return Class descriptor. + * @throws IOException If serial version UID failed. + * @throws ClassNotFoundException If the class cannot be located by the specified class loader. + */ + static GridOptimizedClassDescriptor readClass(DataInput in, ClassLoader clsLdr) + throws IOException, ClassNotFoundException { + assert in != null; + assert clsLdr != null; + + int hdr = in.readByte() & 0xff; + + if (hdr < ggxId2name.length) { + T2<Class<?>, GridOptimizedClassDescriptor> ggxT = ggxId2name[hdr]; + + GridOptimizedClassDescriptor desc = ggxT.get2(); + + if (desc == null) { + desc = GridOptimizedMarshallerUtils.classDescriptor(ggxT.get1(), null); + + ggxT.set2(desc); + } + + return desc; + } + + String name; + Class<?> cls; + GridOptimizedClassDescriptor desc; + + switch (hdr) { + case HEADER_GG_NAME: + int ggId = in.readInt(); + + T3<String, Class<?>, GridOptimizedClassDescriptor> ggT; + + try { + ggT = ggId2name[ggId]; + } + catch (ArrayIndexOutOfBoundsException e) { + throw new ClassNotFoundException("Failed to find optimized class ID " + + "(is same GridGain version running on all nodes?): " + ggId, e); + } + + name = ggT.get1(); + cls = ggT.get2(); + desc = ggT.get3(); + + if (desc == null) { + if (clsLdr == U.gridClassLoader()) { + if (cls == null) { + cls = forName(name, clsLdr); + + ggT.set2(cls); + } + + desc = GridOptimizedMarshallerUtils.classDescriptor(cls, null); + + ggT.set3(desc); + } + else { + cls = forName(name, clsLdr); + + desc = GridOptimizedMarshallerUtils.classDescriptor(cls, null); + } + } + + break; + + case HEADER_USER_NAME: + int usrId = in.readInt(); + + T3<String, Class<?>, GridOptimizedClassDescriptor> usrT; + + try { + if (usrId2Name != null) + usrT = usrId2Name[usrId]; + else + throw new ClassNotFoundException("Failed to find user defined class ID " + + "(make sure to register identical classes on all nodes for optimization): " + usrId); + } + catch (ArrayIndexOutOfBoundsException e) { + throw new ClassNotFoundException("Failed to find user defined class ID " + + "(make sure to register identical classes on all nodes for optimization): " + usrId, e); + } + + name = usrT.get1(); + cls = usrT.get2(); + desc = usrT.get3(); + + if (desc == null) { + if (cls == null) { + cls = forName(name, clsLdr); + + usrT.set2(cls); + } + + desc = GridOptimizedMarshallerUtils.classDescriptor(cls, null); + + usrT.set3(desc); + } + + break; + + case HEADER_ARRAY: + name = readClass(in, clsLdr).name(); + + name = name.charAt(0) == '[' ? "[" + name : "[L" + name + ';'; + + cls = forName(name, clsLdr); + + return GridOptimizedMarshallerUtils.classDescriptor(cls, null); + + case HEADER_NAME: + name = in.readUTF(); + + cls = forName(name, clsLdr); + + desc = GridOptimizedMarshallerUtils.classDescriptor(cls, null); + + break; + + default: + throw new IOException("Unexpected optimized stream header: " + hdr); + } + + short actual = desc.shortId(); + + short exp = in.readShort(); + + if (actual != exp) + throw new ClassNotFoundException("Optimized stream class checksum mismatch " + + "(is same version of marshalled class present on all nodes?) " + + "[expected=" + exp + ", actual=" + actual + ", cls=" + cls + ']'); + + return desc; + } + + /** + * @param out Output. + * @param desc Class descriptor. + * @throws IOException In case of error. + */ + static void writeClass(DataOutput out, GridOptimizedClassDescriptor desc) throws IOException { + assert out != null; + assert desc != null; + + int hdr = desc.header(); + + out.writeByte(hdr); + + switch (hdr) { + case HEADER_GG_NAME: + case HEADER_USER_NAME: + out.writeInt(desc.id()); + out.writeShort(desc.shortId()); + + return; + + case HEADER_ARRAY: + writeClass(out, GridOptimizedMarshallerUtils.classDescriptor(desc.componentType(), null)); + + return; + + case HEADER_NAME: + out.writeUTF(desc.name()); + out.writeShort(desc.shortId()); + } + } + + /** + * @param cls Class to write. + * @return Data for {@code writeClass} method. + */ + static T2<Integer, Integer> writeClassData(Class<?> cls) { + assert cls != null; + + String name = cls.getName(); + + Integer superHdr = ggxName2id.get(name); + + if (superHdr != null) + return new T2<>(superHdr, null); + + Integer id; + + if ((id = ggName2id.get(name)) != null) + return new T2<>(HEADER_GG_NAME, id); + + if (usrName2Id != null && (id = usrName2Id.get(name)) != null) + return new T2<>(HEADER_USER_NAME, id); + + if (cls.isArray()) + return new T2<>(HEADER_ARRAY, null); + + return new T2<>(HEADER_NAME, null); + } + + /** + * @param name Class name. + * @param ldr Class loader. + * @return Class. + * @throws ClassNotFoundException If class not found. + */ + private static Class<?> forName(String name, ClassLoader ldr) throws ClassNotFoundException { + Class<?> cls = primitive(name); + + if (cls == null) + cls = GridOptimizedMarshallerUtils.forName(name, ldr); + + return cls; + } + + /** + * @param name Name of primitive class. + * @return Primitive type class or null. + */ + @SuppressWarnings("TypeMayBeWeakened") + @Nullable private static Class<?> primitive(String name) { + if (name.length() > 7) + return null; + + switch (name.charAt(0)) { + case 'b': + if ("boolean".equals(name)) + return boolean.class; + + return "byte".equals(name) ? byte.class : null; + case 's': + return "short".equals(name) ? short.class : null; + case 'i': + return "int".equals(name) ? int.class : null; + case 'l': + return "long".equals(name) ? long.class : null; + case 'c': + return "char".equals(name) ? char.class : null; + case 'f': + return "float".equals(name) ? float.class : null; + case 'd': + return "double".equals(name) ? double.class : null; + case 'v': + return "void".equals(name) ? void.class : null; + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedFieldType.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedFieldType.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedFieldType.java new file mode 100644 index 0000000..f080a87 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedFieldType.java @@ -0,0 +1,42 @@ +/* @java.file.header */ + +/* _________ _____ __________________ _____ + * __ ____/___________(_)______ /__ ____/______ ____(_)_______ + * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \ + * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / / + * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/ + */ + +package org.apache.ignite.marshaller.optimized; + +/** + * Field type used to calculate {@code Unsafe} offsets into objects. + */ +enum GridOptimizedFieldType { + /** */ + BYTE, + + /** */ + SHORT, + + /** */ + INT, + + /** */ + LONG, + + /** */ + FLOAT, + + /** */ + DOUBLE, + + /** */ + CHAR, + + /** */ + BOOLEAN, + + /** */ + OTHER +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshallable.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshallable.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshallable.java new file mode 100644 index 0000000..2851316 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshallable.java @@ -0,0 +1,57 @@ +/* @java.file.header */ + +/* _________ _____ __________________ _____ + * __ ____/___________(_)______ /__ ____/______ ____(_)_______ + * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \ + * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / / + * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/ + */ + +package org.apache.ignite.marshaller.optimized; + +import java.util.*; + +/** + * Optional interface which helps make serialization even faster by removing internal + * look-ups for classes. + * <p> + * All implementation must have the following: + * <ul> + * <li> + * Must have static filed (private or public) declared of type {@link Object} + * with name {@code GG_CLASS_ID}. GridGain will reflectively initialize this field with + * proper class ID during system startup. + * </li> + * <li> + * Must return the value of {@code GG_CLASS_ID} field from {@link #ggClassId} method. + * </li> + * </ul> + * Here is a sample implementation: + * <pre name="code" class="java"> + * // For better performance consider implementing java.io.Externalizable interface. + * class ExampleMarshallable implements GridOptimizedMarshallable, Serializable { + * // Class ID field required by 'GridOptimizedMarshallable'. + * private static Object GG_CLASS_ID; + * + * ... + * + * @ public Object ggClassId() { + * return GG_CLASS_ID; + * } + * } + * </pre> + * <p> + * Note that for better performance you should also specify list of classes you + * plan to serialize via {@link GridOptimizedMarshaller#setClassNames(List)} method. + */ +public interface GridOptimizedMarshallable { + /** */ + public static final String CLS_ID_FIELD_NAME = "GG_CLASS_ID"; + + /** + * Implementation of this method should simply return value of {@code GG_CLASS_ID} field. + * + * @return Class ID for optimized marshalling. + */ + public Object ggClassId(); +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/a50fccdd/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshaller.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshaller.java new file mode 100644 index 0000000..3a94bb3 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/GridOptimizedMarshaller.java @@ -0,0 +1,408 @@ +/* @java.file.header */ + +/* _________ _____ __________________ _____ + * __ ____/___________(_)______ /__ ____/______ ____(_)_______ + * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \ + * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / / + * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/ + */ + +package org.apache.ignite.marshaller.optimized; + +import org.apache.ignite.marshaller.*; +import org.gridgain.grid.*; +import org.gridgain.grid.util.*; +import org.gridgain.grid.util.typedef.*; +import org.gridgain.grid.util.typedef.internal.*; +import org.jetbrains.annotations.*; +import sun.misc.*; + +import java.io.*; +import java.net.*; +import java.util.*; + +/** + * Optimized implementation of {@link GridMarshaller}. Unlike {@link org.apache.ignite.marshaller.jdk.GridJdkMarshaller}, + * which is based on standard {@link ObjectOutputStream}, this marshaller does not + * enforce that all serialized objects implement {@link Serializable} interface. It is also + * about 20 times faster as it removes lots of serialization overhead that exists in + * default JDK implementation. + * <p> + * {@code GridOptimizedMarshaller} is tested only on Java HotSpot VM on other VMs + * it could yield unexpected results. It is the default marshaller on Java HotSpot VMs + * and will be used if no other marshaller was explicitly configured. + * <p> + * <h1 class="header">Configuration</h1> + * <h2 class="header">Mandatory</h2> + * This marshaller has no mandatory configuration parameters. + * <h2 class="header">Java Example</h2> + * <pre name="code" class="java"> + * GridOptimizedMarshaller marshaller = new GridOptimizedMarshaller(); + * + * // Enforce Serializable interface. + * marshaller.setRequireSerializable(true); + * + * GridConfiguration cfg = new GridConfiguration(); + * + * // Override marshaller. + * cfg.setMarshaller(marshaller); + * + * // Starts grid. + * G.start(cfg); + * </pre> + * <h2 class="header">Spring Example</h2> + * GridOptimizedMarshaller can be configured from Spring XML configuration file: + * <pre name="code" class="xml"> + * <bean id="grid.custom.cfg" class="org.gridgain.grid.GridConfiguration" singleton="true"> + * ... + * <property name="marshaller"> + * <bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller"> + * <property name="requireSerializable">true</property> + * </bean> + * </property> + * ... + * </bean> + * </pre> + * <p> + * <img src="http://www.gridgain.com/images/spring-small.png"> + * <br> + * For information about Spring framework visit <a href="http://www.springframework.org/">www.springframework.org</a> + * <h2 class="header">Injection Example</h2> + * GridMarshaller can be injected in users task, job or SPI as following: + * <pre name="code" class="java"> + * public class MyGridJob implements GridComputeJob { + * ... + * @GridMarshallerResource + * private GridMarshaller marshaller; + * ... + * } + * </pre> + * or + * <pre name="code" class="java"> + * public class MyGridJob implements GridComputeJob { + * ... + * private GridMarshaller marshaller; + * ... + * @GridMarshallerResource + * public void setMarshaller(GridMarshaller marshaller) { + * this.marshaller = marshaller; + * } + * ... + * } + * </pre> + */ +public class GridOptimizedMarshaller extends GridAbstractMarshaller { + /** Whether or not to require an object to be serializable in order to be marshalled. */ + private boolean requireSer = true; + + /** Default class loader. */ + private final ClassLoader dfltClsLdr = getClass().getClassLoader(); + + /** + * Initializes marshaller not to enforce {@link Serializable} interface. + * + * @throws GridRuntimeException If this marshaller is not supported on the current JVM. + */ + public GridOptimizedMarshaller() { + if (!available()) + throw new GridRuntimeException("Using GridOptimizedMarshaller on unsupported JVM version (some of " + + "JVM-private APIs required for the marshaller to work are missing)."); + } + + /** + * Initializes marshaller with given serialization flag. If {@code true}, + * then objects will be required to implement {@link Serializable} in order + * to be serialize. + * + * @param requireSer Flag to enforce {@link Serializable} interface or not. If {@code true}, + * then objects will be required to implement {@link Serializable} in order to be + * marshalled, if {@code false}, then such requirement will be relaxed. + * @throws GridRuntimeException If this marshaller is not supported on the current JVM. + */ + public GridOptimizedMarshaller(boolean requireSer) { + this(); + + this.requireSer = requireSer; + } + + /** + * Initializes marshaller with given serialization flag. If {@code true}, + * then objects will be required to implement {@link Serializable} in order + * to be serialize. + * + * @param requireSer Flag to enforce {@link Serializable} interface or not. If {@code true}, + * then objects will be required to implement {@link Serializable} in order to be + * marshalled, if {@code false}, then such requirement will be relaxed. + * @param clsNames User preregistered class names. + * @param clsNamesPath Path to a file with user preregistered class names. + * @param poolSize Object streams pool size. + * @throws GridException If an I/O error occurs while writing stream header. + * @throws GridRuntimeException If this marshaller is not supported on the current JVM. + */ + public GridOptimizedMarshaller(boolean requireSer, @Nullable List<String> clsNames, + @Nullable String clsNamesPath, int poolSize) throws GridException { + this(requireSer); + + setClassNames(clsNames); + setClassNamesPath(clsNamesPath); + setPoolSize(poolSize); + } + + /** + * Adds provided class names for marshalling optimization. + * <p> + * <b>NOTE</b>: these collections of classes must be identical on all nodes and in the same order. + * + * @param clsNames User preregistered class names to add. + */ + @SuppressWarnings("unchecked") + public void setClassNames(@Nullable List<String> clsNames) { + if (clsNames != null && !clsNames.isEmpty()) { + String[] clsNamesArr = clsNames.toArray(new String[clsNames.size()]); + + Arrays.sort(clsNamesArr); + + Map<String, Integer> name2id = U.newHashMap(clsNamesArr.length); + T3<String, Class<?>, GridOptimizedClassDescriptor>[] id2name = new T3[clsNamesArr.length]; + + int i = 0; + + for (String name : clsNamesArr) { + name2id.put(name, i); + id2name[i++] = new T3<>(name, null, null); + } + + GridOptimizedClassResolver.userClasses(name2id, id2name); + } + } + + /** + * Specifies a name of the file which lists all class names to be optimized. + * The file path can either be absolute path, relative to {@code GRIDGAIN_HOME}, + * or specify a resource file on the class path. + * <p> + * The format of the file is class name per line, like this: + * <pre> + * ... + * com.example.Class1 + * com.example.Class2 + * ... + * </pre> + * <p> + * <b>NOTE</b>: this class list must be identical on all nodes and in the same order. + * + * @param path Path to a file with user preregistered class names. + * @throws GridException If an error occurs while writing stream header. + */ + public void setClassNamesPath(@Nullable String path) throws GridException { + if (path == null) + return; + + URL url = GridUtils.resolveGridGainUrl(path, false); + + if (url == null) + throw new GridException("Failed to find resource for name: " + path); + + List<String> clsNames; + + try { + clsNames = new LinkedList<>(); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), GridOptimizedMarshallerUtils.UTF_8))) { + String clsName; + + while ((clsName = reader.readLine()) != null) + clsNames.add(clsName); + } + } + catch (IOException e) { + throw new GridException("Failed to read class names from path: " + path, e); + } + + setClassNames(clsNames); + } + + /** + * 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, + * therefore, decrease memory consumption. + * <p> + * NOTE: Using streams pool can decrease performance since streams will be shared between + * different threads which will lead to more frequent context switching. + * + * @param poolSize Streams pool size. If {@code 0}, pool is not used. + */ + public void setPoolSize(int poolSize) { + GridOptimizedObjectStreamRegistry.poolSize(poolSize); + } + + /** + * @return Whether to enforce {@link Serializable} interface. + */ + public boolean isRequireSerializable() { + return requireSer; + } + + /** + * Sets flag to enforce {@link Serializable} interface or not. + * + * @param requireSer Flag to enforce {@link Serializable} interface or not. If {@code true}, + * then objects will be required to implement {@link Serializable} in order to be + * marshalled, if {@code false}, then such requirement will be relaxed. + */ + public void setRequireSerializable(boolean requireSer) { + this.requireSer = requireSer; + } + + /** {@inheritDoc} */ + @Override public void marshal(@Nullable Object obj, OutputStream out) throws GridException { + assert out != null; + + GridOptimizedObjectOutputStream objOut = null; + + try { + objOut = GridOptimizedObjectStreamRegistry.out(); + + objOut.requireSerializable(requireSer); + + objOut.out().outputStream(out); + + objOut.writeObject(obj); + } + catch (IOException e) { + throw new GridException("Failed to serialize object: " + obj, e); + } + finally { + GridOptimizedObjectStreamRegistry.closeOut(objOut); + } + } + + /** {@inheritDoc} */ + @Override public byte[] marshal(@Nullable Object obj) throws GridException { + GridOptimizedObjectOutputStream objOut = null; + + try { + objOut = GridOptimizedObjectStreamRegistry.out(); + + objOut.requireSerializable(requireSer); + + objOut.writeObject(obj); + + return objOut.out().array(); + } + catch (IOException e) { + throw new GridException("Failed to serialize object: " + obj, e); + } + finally { + GridOptimizedObjectStreamRegistry.closeOut(objOut); + } + } + + /** {@inheritDoc} */ + @Override public <T> T unmarshal(InputStream in, @Nullable ClassLoader clsLdr) throws GridException { + assert in != null; + + GridOptimizedObjectInputStream objIn = null; + + try { + objIn = GridOptimizedObjectStreamRegistry.in(); + + objIn.classLoader(clsLdr != null ? clsLdr : dfltClsLdr); + + objIn.in().inputStream(in); + + return (T)objIn.readObject(); + } + catch (IOException e) { + throw new GridException("Failed to deserialize object with given class loader: " + clsLdr, e); + } + catch (ClassNotFoundException e) { + throw new GridException("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 { + GridOptimizedObjectStreamRegistry.closeIn(objIn); + } + } + + /** {@inheritDoc} */ + @Override public <T> T unmarshal(byte[] arr, @Nullable ClassLoader clsLdr) throws GridException { + assert arr != null; + + GridOptimizedObjectInputStream objIn = null; + + try { + objIn = GridOptimizedObjectStreamRegistry.in(); + + objIn.classLoader(clsLdr != null ? clsLdr : dfltClsLdr); + + objIn.in().bytes(arr, arr.length); + + return (T)objIn.readObject(); + } + catch (IOException e) { + throw new GridException("Failed to deserialize object with given class loader: " + clsLdr, e); + } + catch (ClassNotFoundException e) { + throw new GridException("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 { + GridOptimizedObjectStreamRegistry.closeIn(objIn); + } + } + + /** + * Checks whether {@code GridOptimizedMarshaller} is able to work on the current JVM. + * <p> + * As long as {@code GridOptimizedMarshaller} uses JVM-private API, which is not guaranteed + * to be available on all JVM, this method should be called to ensure marshaller could work properly. + * <p> + * Result of this method is automatically checked in constructor. + * + * @return {@code true} if {@code GridOptimizedMarshaller} can work on the current JVM or + * {@code false} if it can't. + */ + @SuppressWarnings({"TypeParameterExtendsFinalClass", "ErrorNotRethrown"}) + public static boolean available() { + try { + Unsafe unsafe = GridUnsafe.unsafe(); + + Class<? extends Unsafe> unsafeCls = unsafe.getClass(); + + unsafeCls.getMethod("allocateInstance", Class.class); + unsafeCls.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class); + + return true; + } + catch (Exception ignored) { + return false; + } + catch (NoClassDefFoundError ignored) { + return false; + } + } + + /** + * Undeployment callback invoked when class loader is being undeployed. + * + * @param ldr Class loader being undeployed. + */ + public static void onUndeploy(ClassLoader ldr) { + GridOptimizedMarshallerUtils.onUndeploy(ldr); + } + + /** + * Clears internal caches and frees memory. Usually called on system stop. + */ + public static void clearCache() { + GridOptimizedMarshallerUtils.clearCache(); + } +}