You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/06/16 15:45:13 UTC
[1/3] incubator-ignite git commit: ignite-950: checking whether a
footer is supported for object or not
Repository: incubator-ignite
Updated Branches:
refs/heads/ignite-950 204a408f9 -> 9e2943db8
ignite-950: checking whether a footer is supported for object or not
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/549a1a71
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/549a1a71
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/549a1a71
Branch: refs/heads/ignite-950
Commit: 549a1a716b5e618606e5fea30174bb2fea27f04a
Parents: 204a408
Author: Denis Magda <dm...@gridgain.com>
Authored: Tue Jun 16 11:13:19 2015 +0300
Committer: Denis Magda <dm...@gridgain.com>
Committed: Tue Jun 16 11:13:19 2015 +0300
----------------------------------------------------------------------
.../cacheobject/IgniteCacheObjectProcessor.java | 11 +++
.../IgniteCacheObjectProcessorImpl.java | 80 ++++++++++++++++++--
.../optimized/OptimizedClassDescriptor.java | 30 +++++---
.../optimized/OptimizedMarshaller.java | 21 +++++
.../optimized/OptimizedMarshallerUtils.java | 10 ++-
.../optimized/OptimizedObjectInputStream.java | 10 ++-
.../optimized/OptimizedObjectOutputStream.java | 29 ++++---
7 files changed, 160 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 dc0d1e5..c339037 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
@@ -97,6 +97,17 @@ public interface IgniteCacheObjectProcessor extends GridProcessor {
public boolean hasField(Object obj, String fieldName);
/**
+ * 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.
+ * @throws IgniteCheckedException If failed.
+ */
+ public boolean footerSupported(Object obj) throws IgniteCheckedException;
+
+ /**
* @param ctx Cache object context.
* @param val Value.
* @return Value bytes.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 c9f3444..a002d36 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
@@ -27,10 +27,13 @@ import org.apache.ignite.internal.processors.query.*;
import org.apache.ignite.internal.util.*;
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.jetbrains.annotations.*;
import java.math.*;
import java.util.*;
+import java.util.concurrent.*;
import static org.apache.ignite.cache.CacheMemoryMode.*;
@@ -44,6 +47,21 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme
/** Immutable classes. */
private static final Collection<Class<?>> IMMUTABLE_CLS = new HashSet<>();
+ /** */
+ private static final OptimizedObjectMetadata EMPTY_META = new OptimizedObjectMetadata();
+
+ /** */
+ private volatile IgniteCacheProxy<OptimizedObjectMetadataKey, OptimizedObjectMetadata> metaDataCache;
+
+ /** Metadata updates collected before metadata cache is initialized. */
+ private final ConcurrentHashMap<Integer, OptimizedObjectMetadata> metaBuf = new ConcurrentHashMap<>();
+
+ /** */
+ private final CountDownLatch startLatch = new CountDownLatch(1);
+
+ /** */
+ private OptimizedMarshaller optMarsh;
+
/**
*
*/
@@ -62,6 +80,58 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme
IMMUTABLE_CLS.add(BigDecimal.class);
}
+ /** {@inheritDoc} */
+ @Override public void start() throws IgniteCheckedException {
+ super.start();
+
+ Marshaller marsh = ctx.config().getMarshaller();
+
+ if (marsh instanceof OptimizedMarshaller) {
+ optMarsh = (OptimizedMarshaller)marsh;
+
+ OptimizedObjectMetadataHandler metaHandler = new OptimizedObjectMetadataHandler() {
+ @Override public void addMeta(int typeId, OptimizedObjectMetadata meta) {
+ if (metaBuf.contains(typeId))
+ return;
+
+ metaBuf.put(typeId, meta);
+
+ if (metaDataCache != null)
+ metaDataCache.putIfAbsent(new OptimizedObjectMetadataKey(typeId), meta);
+ }
+
+ @Override public OptimizedObjectMetadata metadata(int typeId) {
+ if (metaDataCache == null)
+ U.awaitQuiet(startLatch);
+
+ OptimizedObjectMetadata meta = metaBuf.get(typeId);
+
+ if (meta != null)
+ return meta == EMPTY_META ? null : meta;
+
+ meta = metaDataCache.localPeek(new OptimizedObjectMetadataKey(typeId));
+
+ if (meta == null)
+ meta = EMPTY_META;
+
+ return meta == EMPTY_META ? null : meta;
+ }
+ };
+
+ optMarsh.setMetadataHandler(metaHandler);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onUtilityCacheStarted() throws IgniteCheckedException {
+ metaDataCache = ctx.cache().jcache(CU.UTILITY_CACHE_NAME);
+
+ startLatch.countDown();
+
+ for (Map.Entry<Integer, OptimizedObjectMetadata> e : metaBuf.entrySet())
+ metaDataCache.putIfAbsent(new OptimizedObjectMetadataKey(e.getKey()), e.getValue());
+ }
+
/**
* @param ctx Context.
*/
@@ -213,11 +283,6 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme
}
/** {@inheritDoc} */
- @Override public void onUtilityCacheStarted() throws IgniteCheckedException {
- // No-op.
- }
-
- /** {@inheritDoc} */
@Override public int typeId(String typeName) {
return 0;
}
@@ -253,6 +318,11 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme
return false;
}
+ /** {@inheritDoc} */
+ @Override public boolean footerSupported(Object obj) throws IgniteCheckedException {
+ return optMarsh != null && optMarsh.footerSupported(obj);
+ }
+
/**
* Wraps key provided by user, must be serialized before stored in cache.
*/
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 ba3dfcf..0ef39b1 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
@@ -119,6 +119,8 @@ class OptimizedClassDescriptor {
* @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")
@@ -127,7 +129,8 @@ class OptimizedClassDescriptor {
ConcurrentMap<Class, OptimizedClassDescriptor> clsMap,
MarshallerContext ctx,
OptimizedMarshallerIdMapper mapper,
- OptimizedObjectMetadataHandler metaHandler)
+ OptimizedObjectMetadataHandler metaHandler,
+ boolean tryEnableMeta)
throws IOException {
this.cls = cls;
this.typeId = typeId;
@@ -487,7 +490,7 @@ class OptimizedClassDescriptor {
this.fields = new Fields(fields, fieldsIndexingEnabled);
- if (fieldsIndexingEnabled && metaHandler.metadata(typeId) == null) {
+ if (tryEnableMeta && fieldsIndexingEnabled && metaHandler.metadata(typeId) == null) {
OptimizedObjectMetadata meta = new OptimizedObjectMetadata();
for (ClassFields clsFields : this.fields.fields)
@@ -496,9 +499,6 @@ class OptimizedClassDescriptor {
U.debug("putting to cache: " + typeId);
- if (typeId == 2104067130) {
- System.out.println();
- }
metaHandler.addMeta(typeId, meta);
U.debug("put to cache: " + typeId);
@@ -659,9 +659,8 @@ class OptimizedClassDescriptor {
case OBJ_ARR:
OptimizedClassDescriptor compDesc = classDescriptor(clsMap,
- obj.getClass().getComponentType(),
- ctx,
- mapper, metaHandler);
+ obj.getClass().getComponentType(), ctx,
+ mapper, metaHandler, false);
compDesc.writeTypeData(out);
@@ -720,7 +719,8 @@ class OptimizedClassDescriptor {
break;
case CLS:
- OptimizedClassDescriptor clsDesc = classDescriptor(clsMap, (Class<?>)obj, ctx, mapper, metaHandler);
+ OptimizedClassDescriptor clsDesc = classDescriptor(clsMap, (Class<?>)obj, ctx, mapper, metaHandler,
+ false);
clsDesc.writeTypeData(out);
@@ -815,6 +815,18 @@ class OptimizedClassDescriptor {
}
/**
+ * Returns type ID.
+ *
+ * @return Type ID.
+ */
+ public int typeId() {
+ if (typeId == 0)
+ return resolveTypeId(cls.getName(), mapper);
+
+ return typeId;
+ }
+
+ /**
* @param cls Class.
* @return Type.
*/
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 a4971c4..4e5b1a7 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
@@ -144,6 +144,7 @@ public class OptimizedMarshaller extends AbstractMarshaller {
* 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,
@@ -289,6 +290,26 @@ public class OptimizedMarshaller extends AbstractMarshaller {
}
/**
+ * 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>
* As long as {@code GridOptimizedMarshaller} uses JVM-private API, which is not guaranteed
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 bf6a4fa..138e732 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
@@ -181,6 +181,8 @@ class OptimizedMarshallerUtils {
* @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.
*/
@@ -189,7 +191,8 @@ class OptimizedMarshallerUtils {
Class cls,
MarshallerContext ctx,
OptimizedMarshallerIdMapper mapper,
- OptimizedObjectMetadataHandler metaHandler)
+ OptimizedObjectMetadataHandler metaHandler,
+ boolean tryEnableMeta)
throws IOException
{
OptimizedClassDescriptor desc = clsMap.get(cls);
@@ -206,7 +209,8 @@ class OptimizedMarshallerUtils {
throw new IOException("Failed to register class: " + cls.getName(), e);
}
- desc = new OptimizedClassDescriptor(cls, registered ? typeId : 0, clsMap, ctx, mapper, metaHandler);
+ desc = new OptimizedClassDescriptor(cls, registered ? typeId : 0, clsMap, ctx, mapper, metaHandler,
+ tryEnableMeta);
if (registered) {
OptimizedClassDescriptor old = clsMap.putIfAbsent(cls, desc);
@@ -281,7 +285,7 @@ class OptimizedMarshallerUtils {
if (desc == null) {
OptimizedClassDescriptor old = clsMap.putIfAbsent(cls, desc =
new OptimizedClassDescriptor(cls, resolveTypeId(cls.getName(), mapper), clsMap, ctx, mapper,
- metaHandler));
+ metaHandler, false));
if (old != null)
desc = old;
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 846fb08..70a2f3f 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
@@ -250,7 +250,7 @@ class OptimizedObjectInputStream extends ObjectInputStream {
int typeId = readInt();
OptimizedClassDescriptor desc = typeId == 0 ?
- classDescriptor(clsMap, U.forName(readUTF(), clsLdr), ctx, mapper, metaHandler):
+ classDescriptor(clsMap, U.forName(readUTF(), clsLdr), ctx, mapper, metaHandler, false):
classDescriptor(clsMap, typeId, clsLdr, ctx, mapper, metaHandler);
curCls = desc.describedClass();
@@ -540,10 +540,12 @@ class OptimizedObjectInputStream extends ObjectInputStream {
}
}
- int footerLen = in.readInt();
+ if (metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != null) {
+ int footerLen = in.readInt();
- if (footerLen != EMPTY_FOOTER)
- in.skipBytes(footerLen - 4);
+ if (footerLen != EMPTY_FOOTER)
+ in.skipBytes(footerLen - 4);
+ }
return obj;
}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/549a1a71/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 2ead955..05d3e3d 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
@@ -194,7 +194,8 @@ class OptimizedObjectOutputStream extends ObjectOutputStream {
obj instanceof Object[] ? Object[].class : obj.getClass(),
ctx,
mapper,
- metaHandler);
+ metaHandler,
+ false);
if (desc.excluded()) {
writeByte(NULL);
@@ -220,7 +221,8 @@ class OptimizedObjectOutputStream extends ObjectOutputStream {
obj instanceof Object[] ? Object[].class : obj.getClass(),
ctx,
mapper,
- metaHandler);
+ metaHandler,
+ false);
}
if (handle >= 0) {
@@ -317,9 +319,13 @@ class OptimizedObjectOutputStream extends ObjectOutputStream {
@SuppressWarnings("ForLoopReplaceableByForEach")
void writeSerializable(Object obj, List<Method> mtds, OptimizedClassDescriptor.Fields fields, int headerPos)
throws IOException {
- Footer footer = new Footer(fields);
+ Footer footer = null;
- footer.headerPos(headerPos);
+ if (metaHandler.metadata(resolveTypeId(obj.getClass().getName(), mapper)) != null) {
+ footer = new Footer(fields);
+
+ footer.headerPos(headerPos);
+ }
for (int i = 0; i < mtds.size(); i++) {
Method mtd = mtds.get(i);
@@ -343,7 +349,8 @@ class OptimizedObjectOutputStream extends ObjectOutputStream {
writeFields(obj, fields.fields(i), footer);
}
- footer.write();
+ if (footer != null)
+ footer.write();
}
/**
@@ -553,12 +560,12 @@ class OptimizedObjectOutputStream extends ObjectOutputStream {
if (t.field() != null) {
int handle = writeObject0(getObject(obj, t.offset()));
- if (handle >= 0)
+ if (footer != null && handle >= 0)
footer.disable();
}
}
- if (t.field() != null) {
+ if (footer != null && t.field() != null) {
int fieldLen = out.size() - size;
footer.put(t.id(), t.type(), fieldLen);
@@ -813,13 +820,15 @@ class OptimizedObjectOutputStream extends ObjectOutputStream {
case OTHER:
int handle = writeObject0(t.get2());
- if (handle >= 0)
+ if (footer != null && handle >= 0)
footer.disable();
}
- int fieldLen = out.size() - size;
+ if (footer != null) {
+ int fieldLen = out.size() - size;
- footer.put(t.get1().id(), t.get1().type(), fieldLen);
+ footer.put(t.get1().id(), t.get1().type(), fieldLen);
+ }
}
}
[2/3] incubator-ignite git commit: ignite-950: moved all footer
related logic to dedicated class, unmarshalling enclosed objects,
wrapping serializable fields with CacheObjectImpl
Posted by sb...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadata.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadata.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadata.java
new file mode 100644
index 0000000..7154a25
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadata.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.marshaller.optimized.ext;
+
+import org.apache.ignite.*;
+import org.apache.ignite.marshaller.optimized.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * 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 = OptimizedMarshallerExt.VARIABLE_LEN;
+ break;
+
+ default:
+ throw new IgniteException("Unknown field type: " + fieldType);
+ }
+
+ assert len != 1;
+
+ fieldsInfo.add(new FieldInfo(fieldId, len));
+ }
+
+ /**
+ * Gets {@link 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/ext/OptimizedObjectMetadataKey.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadataKey.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadataKey.java
new file mode 100644
index 0000000..b9fcd58
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectMetadataKey.java
@@ -0,0 +1,70 @@
+/*
+ * 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 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/ext/OptimizedObjectOutputStreamExt.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectOutputStreamExt.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectOutputStreamExt.java
new file mode 100644
index 0000000..823caf5
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectOutputStreamExt.java
@@ -0,0 +1,135 @@
+/*
+ * 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.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 OptimizedObjectOutputStreamExt extends OptimizedObjectOutputStream {
+ /** */
+ private OptimizedMarshallerExtMetaHandler metaHandler;
+
+ /** {@inheritDoc} */
+ protected OptimizedObjectOutputStreamExt(GridDataOutput out) throws IOException {
+ super(out);
+ }
+
+ /**
+ * @param clsMap Class descriptors by class map.
+ * @param ctx Context.
+ * @param mapper ID mapper.
+ * @param requireSer Require {@link Serializable} flag.
+ * @param metaHandler Metadata handler.
+ */
+ protected void context(ConcurrentMap<Class, OptimizedClassDescriptor> clsMap, MarshallerContext ctx,
+ OptimizedMarshallerIdMapper mapper, boolean requireSer, OptimizedMarshallerExtMetaHandler metaHandler) {
+ context(clsMap, ctx, mapper, requireSer);
+
+ this.metaHandler = metaHandler;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeFieldType(byte type) throws IOException {
+ out.writeByte(type);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected Footer createFooter(Class<?> cls) {
+ if (metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != null)
+ return new FooterImpl();
+ else
+ return null;
+ }
+
+ /**
+ *
+ */
+ private class FooterImpl implements OptimizedObjectOutputStream.Footer {
+ /** */
+ private ArrayList<Short> data;
+
+ /** */
+ private int headerPos;
+
+ /** {@inheritDoc} */
+ @Override public void fields(OptimizedClassDescriptor.Fields fields) {
+ if (fields.fieldsIndexingSupported())
+ data = new ArrayList<>();
+ else
+ data = null;
+ }
+
+ /** {@inheritDoc} */
+ public void headerPos(int pos) {
+ headerPos = pos;
+ }
+
+ /** {@inheritDoc} */
+ public void put(int fieldId, OptimizedFieldType fieldType, int len) {
+ if (data == null)
+ return;
+
+ // Considering that field's length will be no longer 2^15 (32 MB)
+ if (fieldType == OptimizedFieldType.OTHER)
+ data.add((short)len);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void putHandle(int fieldId, int handleId) {
+ disable();
+ }
+
+ /** {@inheritDoc} */
+ public 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);
+ }
+ }
+
+ /**
+ * Disable footer and indexing for the given Object.
+ */
+ private void disable() {
+ data = null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectStreamExtRegistry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectStreamExtRegistry.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectStreamExtRegistry.java
new file mode 100644
index 0000000..e07b4de
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/OptimizedObjectStreamExtRegistry.java
@@ -0,0 +1,226 @@
+/*
+ * 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.*;
+import org.apache.ignite.internal.util.io.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.marshaller.optimized.*;
+
+import java.io.*;
+import java.util.concurrent.*;
+
+/**
+ * Storage for object streams.
+ */
+class OptimizedObjectStreamExtRegistry {
+ /** Holders. */
+ private static final ThreadLocal<StreamHolder> holders = new ThreadLocal<>();
+
+ /** Holders pool. */
+ private static BlockingQueue<StreamHolder> pool;
+
+ /**
+ * Ensures singleton.
+ */
+ private OptimizedObjectStreamExtRegistry() {
+ // No-op.
+ }
+
+ /**
+ * Sets streams pool size.
+ *
+ * @param size Streams pool size.
+ */
+ static void poolSize(int size) {
+ if (size > 0) {
+ pool = new LinkedBlockingQueue<>(size);
+
+ for (int i = 0; i < size; i++) {
+ boolean b = pool.offer(new StreamHolder());
+
+ assert b;
+ }
+ }
+ else
+ pool = null;
+ }
+
+ /**
+ * Gets output stream.
+ *
+ * @return Object output stream.
+ * @throws IgniteInterruptedCheckedException If thread is interrupted while trying to take holder from pool.
+ */
+ static OptimizedObjectOutputStreamExt out() throws IgniteInterruptedCheckedException {
+ return holder().acquireOut();
+ }
+
+ /**
+ * Gets input stream.
+ *
+ * @return Object input stream.
+ * @throws IgniteInterruptedCheckedException If thread is interrupted while trying to take holder from pool.
+ */
+ static OptimizedObjectInputStreamExt in() throws IgniteInterruptedCheckedException {
+ return holder().acquireIn();
+ }
+
+ /**
+ * Closes and releases output stream.
+ *
+ * @param out Object output stream.
+ */
+ static void closeOut(OptimizedObjectOutputStream out) {
+ U.close(out, null);
+
+ StreamHolder holder = holders.get();
+
+ holder.releaseOut();
+
+ if (pool != null) {
+ holders.remove();
+
+ boolean b = pool.offer(holder);
+
+ assert b;
+ }
+ }
+
+ /**
+ * Closes and releases input stream.
+ *
+ * @param in Object input stream.
+ */
+ @SuppressWarnings("TypeMayBeWeakened")
+ static void closeIn(OptimizedObjectInputStream in) {
+ U.close(in, null);
+
+ StreamHolder holder = holders.get();
+
+ holder.releaseIn();
+
+ if (pool != null) {
+ holders.remove();
+
+ boolean b = pool.offer(holder);
+
+ assert b;
+ }
+ }
+
+ /**
+ * Gets holder from pool or thread local.
+ *
+ * @return Stream holder.
+ * @throws IgniteInterruptedCheckedException If thread is interrupted while trying to take holder from pool.
+ */
+ private static StreamHolder holder() throws IgniteInterruptedCheckedException {
+ StreamHolder holder = holders.get();
+
+ if (holder == null) {
+ try {
+ holders.set(holder = pool != null ? pool.take() : new StreamHolder());
+ }
+ catch (InterruptedException e) {
+ throw new IgniteInterruptedCheckedException(
+ "Failed to take object stream from pool (thread interrupted).", e);
+ }
+ }
+
+ return holder;
+ }
+
+ /**
+ * Streams holder.
+ */
+ private static class StreamHolder {
+ /** Output stream. */
+ private final OptimizedObjectOutputStreamExt out = createOut();
+
+ /** Input stream. */
+ private final OptimizedObjectInputStreamExt in = createIn();
+
+ /** Output streams counter. */
+ private int outAcquireCnt;
+
+ /** Input streams counter. */
+ private int inAcquireCnt;
+
+ /**
+ * Gets output stream.
+ *
+ * @return Object output stream.
+ */
+ OptimizedObjectOutputStreamExt acquireOut() {
+ return outAcquireCnt++ > 0 ? createOut() : out;
+ }
+
+ /**
+ * Gets input stream.
+ *
+ * @return Object input stream.
+ */
+ OptimizedObjectInputStreamExt acquireIn() {
+ return inAcquireCnt++ > 0 ? createIn() : in;
+ }
+
+ /**
+ * Releases output stream.
+ */
+ void releaseOut() {
+ outAcquireCnt--;
+ }
+
+ /**
+ * Releases input stream.
+ */
+ void releaseIn() {
+ inAcquireCnt--;
+ }
+
+ /**
+ * Creates output stream.
+ *
+ * @return Object output stream.
+ */
+ private OptimizedObjectOutputStreamExt createOut() {
+ try {
+ return new OptimizedObjectOutputStreamExt(new GridUnsafeDataOutput(4 * 1024));
+ }
+ catch (IOException e) {
+ throw new IgniteException("Failed to create object output stream.", e);
+ }
+ }
+
+ /**
+ * Creates input stream.
+ *
+ * @return Object input stream.
+ */
+ private OptimizedObjectInputStreamExt createIn() {
+ try {
+ return new OptimizedObjectInputStreamExt(new GridUnsafeDataInput());
+ }
+ catch (IOException e) {
+ throw new IgniteException("Failed to create object input stream.", e);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/package-info.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
new file mode 100644
index 0000000..294ef7f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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 description. -->
+ * Contains <b>extended</b> Optimized marshaller.
+ */
+package org.apache.ignite.marshaller.optimized.ext;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSelfTest.java
index 6c78506..7d09070 100644
--- a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSelfTest.java
@@ -111,19 +111,6 @@ public class OptimizedMarshallerSelfTest extends GridMarshallerAbstractTest {
}
/**
- * @throws Exception If failed.
- */
- public void testFieldUnmarshalling() throws Exception {
- TestObject2 obj = new TestObject2(5);
-
- byte[] data = marshal(obj);
-
- Integer i = ((OptimizedMarshaller)marsh).unmarshal("i", data, Thread.currentThread().getContextClassLoader());
-
- assertEquals(obj.i, (int)i);
- }
-
- /**
* Class for nested execution test.
*/
private static class NestedTestObject implements Serializable {
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedObjectStreamSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedObjectStreamSelfTest.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedObjectStreamSelfTest.java
index 0324e2f..20391eb 100644
--- a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedObjectStreamSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedObjectStreamSelfTest.java
@@ -18,7 +18,6 @@
package org.apache.ignite.marshaller.optimized;
import org.apache.ignite.*;
-import org.apache.ignite.internal.processors.cache.*;
import org.apache.ignite.internal.util.io.*;
import org.apache.ignite.internal.util.typedef.*;
import org.apache.ignite.internal.util.typedef.internal.*;
@@ -47,17 +46,6 @@ public class OptimizedObjectStreamSelfTest extends GridCommonAbstractTest {
/** */
private ConcurrentMap<Class, OptimizedClassDescriptor> clsMap = new ConcurrentHashMap8<>();
- /** */
- private static final OptimizedObjectMetadataHandler META_HANDLER = new OptimizedObjectMetadataHandler() {
- @Override public void addMeta(int typeId, OptimizedObjectMetadata meta) {
-
- }
-
- @Override public OptimizedObjectMetadata metadata(int typeId) {
- return null;
- }
- };
-
/**
* @throws Exception If failed.
*/
@@ -1033,7 +1021,7 @@ public class OptimizedObjectStreamSelfTest extends GridCommonAbstractTest {
try {
out = OptimizedObjectStreamRegistry.out();
- out.context(clsMap, CTX, null, META_HANDLER, true);
+ out.context(clsMap, CTX, null, true);
out.writeObject(obj);
@@ -1041,7 +1029,7 @@ public class OptimizedObjectStreamSelfTest extends GridCommonAbstractTest {
in = OptimizedObjectStreamRegistry.in();
- in.context(clsMap, CTX, null, META_HANDLER, getClass().getClassLoader());
+ in.context(clsMap, CTX, null, getClass().getClassLoader());
in.in().bytes(arr, arr.length);
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java
new file mode 100644
index 0000000..d663c55
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.marshaller.*;
+import org.apache.ignite.marshaller.optimized.*;
+import org.apache.ignite.testframework.junits.common.*;
+
+import java.util.concurrent.*;
+
+/**
+ * Optimized marshaller self test.
+ */
+@GridCommonTest(group = "Marshaller")
+public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest {
+ /** {@inheritDoc} */
+ @Override protected Marshaller marshaller() {
+ return new OptimizedMarshallerExt(false);
+ }
+
+ /**
+ * @throws Exception In case of error.
+ */
+ public void testHasField() throws Exception {
+ OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
+
+ assertTrue(marsh.putMetaForClass(TestObject.class));
+
+ TestObject testObj = new TestObject("World", 50);
+
+ byte[] arr = marsh.marshal(testObj);
+
+ assertTrue(marsh.hasField("o2", arr, 0, arr.length));
+ assertTrue(marsh.hasField("str", arr, 0, arr.length));
+
+ assertFalse(marsh.hasField("m", arr, 0, arr.length));
+ }
+
+ /**
+ * @throws Exception In case of error.
+ */
+ public void testReadField() throws Exception {
+ OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
+
+ assertTrue(marsh.putMetaForClass(TestObject.class));
+
+ TestObject testObj = new TestObject("World", 50);
+
+ byte[] arr = marsh.marshal(testObj);
+
+ // Simple field extraction.
+
+ String text = marsh.readField("str", arr, 0, arr.length, null);
+
+ assertEquals(testObj.str, text);
+
+ // Serializable extraction (doesn't have meta, thus doesn't have footer)
+ TestObject2 o2 = marsh.readField("o2", arr, 0, arr.length, null);
+
+ assertEquals(testObj.o2, o2);
+
+ // Add metadata for the enclosed object.
+ assertTrue(marsh.putMetaForClass(TestObject2.class));
+
+ arr = marsh.marshal(testObj);
+
+ // Must be returned in a wrapped form, since metadata was added enabling the footer.
+ CacheObjectImpl cacheObject = marsh.readField("o2", arr, 0, arr.length, null);
+
+ arr = cacheObject.valueBytes(null);
+
+ // Check enclosed objects fields
+ assertTrue(marsh.hasField("i", arr, 0, arr.length));
+ assertEquals(testObj.o2.i, (int)marsh.readField("i", arr, 0, arr.length, null));
+ }
+
+ /** */
+ private static class TestObject2 {
+ /** */
+ private final int i;
+
+ /**
+ * Constructor for TestObject2 instances.
+ *
+ * @param i Integer value to hold.
+ */
+ private TestObject2(int i) {
+ this.i = i;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ return i == ((TestObject2)o).i;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return i;
+ }
+ }
+
+ /**
+ * Static nested class.
+ */
+ private static class TestObject {
+ /** */
+ private final TestObject2 o2;
+
+ /** The only meaningful field in the class, used for {@link #equals(Object o)} and {@link #hashCode()}. */
+ private final String str;
+
+ /**
+ * @param str String to hold.
+ * @param i Integer.
+ */
+ TestObject(String str, int i) {
+ this.str = str;
+
+ o2 = new TestObject2(i);
+ }
+
+ /**
+ * Method for accessing value of the hold string after the object is created.
+ *
+ * @return Wrapped string.
+ */
+ public String string() {
+ return str;
+ }
+
+ /**
+ * @return Object held in this wrapped.
+ */
+ public TestObject2 obj() {
+ return o2;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return 31 * o2.hashCode() + str.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("RedundantIfStatement")
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ TestObject obj = (TestObject)o;
+
+ if (o2 != null ? !o2.equals(obj.o2) : obj.o2 != null)
+ return false;
+
+ if (str != null ? !str.equals(obj.str) : obj.str != null)
+ return false;
+
+ return true;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/9e2943db/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
new file mode 100644
index 0000000..eabdbce
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Extended optimized marshaller test package.
+ */
+package org.apache.ignite.marshaller.optimized.ext;
\ No newline at end of file
[3/3] incubator-ignite git commit: ignite-950: moved all footer
related logic to dedicated class, unmarshalling enclosed objects,
wrapping serializable fields with CacheObjectImpl
Posted by sb...@apache.org.
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 <dm...@gridgain.com>
Authored: Tue Jun 16 16:44:55 2015 +0300
Committer: Denis Magda <dm...@gridgain.com>
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;
+ }
+ }
+}