You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2015/07/22 03:29:47 UTC

incubator-ignite git commit: IGNITE-950 - Introduced IgniteObject

Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-950 680ffa0b1 -> d9bceb562


IGNITE-950 - Introduced IgniteObject


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/d9bceb56
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/d9bceb56
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/d9bceb56

Branch: refs/heads/ignite-950
Commit: d9bceb562a8ec1d026e47ed1c076afc43a3cc35a
Parents: 680ffa0
Author: Alexey Goncharuk <ag...@gridgain.com>
Authored: Tue Jul 21 18:29:39 2015 -0700
Committer: Alexey Goncharuk <ag...@gridgain.com>
Committed: Tue Jul 21 18:29:39 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/ignite/IgniteCache.java     |  8 +++
 .../java/org/apache/ignite/IgniteObject.java    | 55 +++++++++++++++++++
 .../processors/cache/CacheIndexedObject.java    | 32 +----------
 .../cache/CacheIndexedObjectImpl.java           | 50 ++++++++++++++---
 .../processors/cache/CacheOperationContext.java | 24 ++++-----
 .../processors/cache/GridCacheAdapter.java      | 18 +++----
 .../processors/cache/GridCacheContext.java      |  4 +-
 .../processors/cache/GridCacheProxyImpl.java    |  6 +--
 .../processors/cache/IgniteCacheProxy.java      | 35 ++++++++++--
 .../processors/cache/IgniteInternalCache.java   | 10 ++--
 .../cache/KeyCacheIndexedObjectImpl.java        | 38 +------------
 .../distributed/dht/GridDhtCacheAdapter.java    |  4 +-
 .../cache/query/GridCacheQueryManager.java      |  2 +-
 .../store/GridCacheStoreManagerAdapter.java     | 12 ++---
 .../transactions/IgniteTxLocalAdapter.java      |  6 +--
 .../IgniteCacheObjectProcessorImpl.java         |  4 +-
 .../processors/query/GridQueryProcessor.java    |  4 +-
 .../optimized/OptimizedClassDescriptor.java     |  2 +
 .../optimized/OptimizedMarshaller.java          |  2 +-
 .../optimized/OptimizedMarshallerUtils.java     | 22 --------
 .../optimized/OptimizedObjectInputStream.java   | 43 ++++++---------
 .../optimized/OptimizedObjectMetadata.java      |  9 ++--
 .../optimized/OptimizedObjectOutputStream.java  | 50 +++++++++++++++--
 .../OptimizedMarshallerExtSelfTest.java         | 57 ++++++++++++++++++--
 .../multijvm/IgniteCacheProcessProxy.java       |  5 ++
 .../processors/query/h2/IgniteH2Indexing.java   |  2 +-
 26 files changed, 314 insertions(+), 190 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
index 4938ab1..fce2777 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
@@ -106,6 +106,14 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS
     public IgniteCache<K, V> withSkipStore();
 
     /**
+     * Returns an instance of cache that will keep binary form of objects on all cache operations when
+     * optimized field marshaller is used.
+     *
+     * @return Instance of Ignite cache preserving binary object format.
+     */
+    public IgniteCache<K, V> withIgniteObject();
+
+    /**
      * @return Cache with no-retries behavior enabled.
      */
     public IgniteCache<K, V> withNoRetries();

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/IgniteObject.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteObject.java b/modules/core/src/main/java/org/apache/ignite/IgniteObject.java
new file mode 100644
index 0000000..c9e1160
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteObject.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import org.jetbrains.annotations.*;
+
+/**
+ * Abstracted binary representation of objects.
+ */
+public interface IgniteObject {
+    /**
+     * Gets portable object type ID.
+     *
+     * @return Type ID.
+     */
+    public int typeId();
+
+    /**
+     * Gets fully deserialized instance of portable object.
+     *
+     * @return Fully deserialized instance of portable object.
+     */
+    @Nullable public <T> T deserialize() throws IgniteException;
+
+    /**
+     * Gets field value.
+     *
+     * @param fieldName Field name.
+     * @return Field value.
+     */
+    @Nullable public <T> T field(String fieldName);
+
+    /**
+     * Checks whether field is set.
+     *
+     * @param fieldName Field name.
+     * @return {@code true} if field is set.
+     */
+    public boolean hasField(String fieldName);
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObject.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObject.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObject.java
index de931a2..0cf0dee 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObject.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObject.java
@@ -23,34 +23,6 @@ import org.jetbrains.annotations.*;
 /**
  *
  */
-public interface CacheIndexedObject extends CacheObject {
-    /**
-     * Gets portable object type ID.
-     *
-     * @return Type ID.
-     */
-    public int typeId();
-
-    /**
-     * Gets fully deserialized instance of portable object.
-     *
-     * @return Fully deserialized instance of portable object.
-     */
-    @Nullable public <T> T deserialize() throws IgniteException;
-
-    /**
-     * Gets field value.
-     *
-     * @param fieldName Field name.
-     * @return Field value.
-     */
-    @Nullable public <T> T field(String fieldName);
-
-    /**
-     * Checks whether field is set.
-     *
-     * @param fieldName Field name.
-     * @return {@code true} if field is set.
-     */
-    public boolean hasField(String fieldName);
+public interface CacheIndexedObject extends CacheObject, IgniteObject {
+    // All required method are declared in IgniteObject.
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java
index 852f9df..c85e2c9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheIndexedObjectImpl.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.*;
 import org.apache.ignite.internal.util.*;
+import org.apache.ignite.internal.util.typedef.*;
 import org.apache.ignite.marshaller.optimized.*;
 import org.apache.ignite.plugin.extensions.communication.*;
 import org.jetbrains.annotations.*;
@@ -27,6 +28,8 @@ import sun.misc.*;
 import java.io.*;
 import java.nio.*;
 
+import static org.apache.ignite.marshaller.optimized.OptimizedObjectOutputStream.*;
+
 /**
  * Cache object implementation for classes that support footer injection is their serialized form thus enabling fields
  * search and extraction without necessity to fully deserialize an object.
@@ -108,7 +111,7 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter implements CacheI
 
     /** {@inheritDoc} */
     @Override public byte[] valueBytes(CacheObjectContext ctx) throws IgniteCheckedException {
-        toMarshaledFormIfNeeded(ctx);
+        toMarshaledFormIfNeeded();
 
         return valBytes;
     }
@@ -130,7 +133,7 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter implements CacheI
 
     /** {@inheritDoc} */
     @Override public void prepareMarshal(CacheObjectContext ctx) throws IgniteCheckedException {
-        toMarshaledFormIfNeeded(ctx);
+        toMarshaledFormIfNeeded();
     }
 
     /** {@inheritDoc} */
@@ -309,25 +312,56 @@ public class CacheIndexedObjectImpl extends CacheObjectAdapter implements CacheI
 
     /** {@inheritDoc} */
     @Override public int hashCode() {
-        assert false;
+        if (val != null)
+            return val.hashCode();
+        else {
+            assert valBytes != null;
 
-        return super.hashCode();
+            return UNSAFE.getInt(valBytes, BYTE_ARR_OFF + start + len -
+                FOOTER_LENGTH_FIELD_SIZE - FOOTER_HANDLES_FIELD_SIZE - FOOTER_OBJECT_HASH_CODE_FIELD_SIZE);
+        }
     }
 
     /** {@inheritDoc} */
     @Override public boolean equals(Object obj) {
-        assert false;
+        if (obj == this)
+            return true;
+
+        if (!(obj instanceof CacheIndexedObjectImpl))
+            return false;
+
+        CacheIndexedObjectImpl other = (CacheIndexedObjectImpl)obj;
+
+        try {
+            if (val != null && other.val != null)
+                return F.eq(val, other.val);
+            else {
+                toMarshaledFormIfNeeded();
 
-        return super.equals(obj);
+                other.toMarshaledFormIfNeeded();
+
+                if (len != other.len)
+                    return false;
+
+                for (int i = 0; i < len; i++) {
+                    if (valBytes[start + i] != other.valBytes[other.start + i])
+                        return false;
+                }
+
+                return true;
+            }
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException(e);
+        }
     }
 
     /**
      * Marshals {@link #val} to {@link #valBytes} if needed.
      *
-     * @param ctx Cache object context.
      * @throws IgniteCheckedException In case of error.
      */
-    protected void toMarshaledFormIfNeeded(CacheObjectContext ctx) throws IgniteCheckedException {
+    protected void toMarshaledFormIfNeeded() throws IgniteCheckedException {
         if (valBytes == null) {
             assert val != null;
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOperationContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOperationContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOperationContext.java
index 343a2f0..0f9935d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOperationContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOperationContext.java
@@ -44,7 +44,7 @@ public class CacheOperationContext implements Serializable {
     private final UUID subjId;
 
     /** Keep portable flag. */
-    private final boolean keepPortable;
+    private final boolean keepIgniteObject;
 
     /** Expiry policy. */
     private final ExpiryPolicy expiryPlc;
@@ -57,7 +57,7 @@ public class CacheOperationContext implements Serializable {
 
         subjId = null;
 
-        keepPortable = false;
+        keepIgniteObject = false;
 
         expiryPlc = null;
 
@@ -67,20 +67,20 @@ public class CacheOperationContext implements Serializable {
     /**
      * @param skipStore Skip store flag.
      * @param subjId Subject ID.
-     * @param keepPortable Keep portable flag.
+     * @param keepIgniteObject Keep portable flag.
      * @param expiryPlc Expiry policy.
      */
     public CacheOperationContext(
         boolean skipStore,
         @Nullable UUID subjId,
-        boolean keepPortable,
+        boolean keepIgniteObject,
         @Nullable ExpiryPolicy expiryPlc,
         boolean noRetries) {
         this.skipStore = skipStore;
 
         this.subjId = subjId;
 
-        this.keepPortable = keepPortable;
+        this.keepIgniteObject = keepIgniteObject;
 
         this.expiryPlc = expiryPlc;
 
@@ -90,16 +90,16 @@ public class CacheOperationContext implements Serializable {
     /**
      * @return Keep portable flag.
      */
-    public boolean isKeepPortable() {
-        return keepPortable;
+    public boolean isKeepIgniteObject() {
+        return keepIgniteObject;
     }
 
     /**
-     * See {@link IgniteInternalCache#keepPortable()}.
+     * See {@link IgniteInternalCache#keepIgniteObject()}.
      *
      * @return New instance of CacheOperationContext with keep portable flag.
      */
-    public CacheOperationContext keepPortable() {
+    public CacheOperationContext keepIgniteObject() {
         return new CacheOperationContext(
             skipStore,
             subjId,
@@ -127,7 +127,7 @@ public class CacheOperationContext implements Serializable {
         return new CacheOperationContext(
             skipStore,
             subjId,
-            keepPortable,
+            keepIgniteObject,
             expiryPlc,
             noRetries);
     }
@@ -149,7 +149,7 @@ public class CacheOperationContext implements Serializable {
         return new CacheOperationContext(
             skipStore,
             subjId,
-            keepPortable,
+            keepIgniteObject,
             expiryPlc,
             noRetries);
     }
@@ -184,7 +184,7 @@ public class CacheOperationContext implements Serializable {
         return new CacheOperationContext(
             skipStore,
             subjId,
-            keepPortable,
+            keepIgniteObject,
             expiryPlc,
             noRetries
         );

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
index eded9bf..76e8156 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
@@ -384,7 +384,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     }
 
     /** {@inheritDoc} */
-    @Override public <K1, V1> GridCacheProxyImpl<K1, V1> keepPortable() {
+    @Override public <K1, V1> GridCacheProxyImpl<K1, V1> keepIgniteObject() {
         CacheOperationContext opCtx = new CacheOperationContext(false, null, true, null, false);
 
         return new GridCacheProxyImpl<>((GridCacheContext<K1, V1>)ctx, (GridCacheAdapter<K1, V1>)this, opCtx);
@@ -593,7 +593,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
             modes.backup = true;
 
             if (modes.heap)
-                its.add(iterator(map.entries0().iterator(), !ctx.keepPortable()));
+                its.add(iterator(map.entries0().iterator(), !ctx.keepIgniteObject()));
         }
         else if (modes.heap) {
             if (modes.near && ctx.isNear())
@@ -727,7 +727,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
             Object val = CU.value(cacheVal, ctx, true);
 
-            val = ctx.unwrapIfNeeded(val, ctx.keepPortable());
+            val = ctx.unwrapIfNeeded(val, ctx.keepIgniteObject());
 
             return (V)val;
         }
@@ -1241,7 +1241,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
             null,
             null,
             taskName,
-            !ctx.keepPortable(),
+            !ctx.keepIgniteObject(),
             false);
     }
 
@@ -1445,7 +1445,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
-        V val = get(key, !ctx.keepPortable());
+        V val = get(key, !ctx.keepIgniteObject());
 
         if (ctx.config().getInterceptor() != null)
             val = (V)ctx.config().getInterceptor().onGet(key, val);
@@ -1464,7 +1464,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
-        IgniteInternalFuture<V> fut = getAsync(key, !ctx.keepPortable());
+        IgniteInternalFuture<V> fut = getAsync(key, !ctx.keepIgniteObject());
 
         if (ctx.config().getInterceptor() != null)
             fut =  fut.chain(new CX1<IgniteInternalFuture<V>, V>() {
@@ -1487,7 +1487,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
-        Map<K, V> map = getAll(keys, !ctx.keepPortable());
+        Map<K, V> map = getAll(keys, !ctx.keepIgniteObject());
 
         if (ctx.config().getInterceptor() != null)
             map = interceptGet(keys, map);
@@ -1506,7 +1506,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
-        IgniteInternalFuture<Map<K, V>> fut = getAllAsync(keys, !ctx.keepPortable());
+        IgniteInternalFuture<Map<K, V>> fut = getAllAsync(keys, !ctx.keepIgniteObject());
 
         if (ctx.config().getInterceptor() != null)
             return fut.chain(new CX1<IgniteInternalFuture<Map<K, V>>, Map<K, V>>() {
@@ -3720,7 +3720,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
         if (!ctx0.isSwapOrOffheapEnabled() && ctx0.kernalContext().discovery().size() == 1)
             return localIteratorHonorExpirePolicy(opCtx);
 
-        CacheQueryFuture<Map.Entry<K, V>> fut = ctx0.queries().createScanQuery(null, null, ctx.keepPortable())
+        CacheQueryFuture<Map.Entry<K, V>> fut = ctx0.queries().createScanQuery(null, null, ctx.keepIgniteObject())
             .keepAll(false)
             .execute();
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index c317b79..8189afd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -1680,10 +1680,10 @@ public class GridCacheContext<K, V> implements Externalizable {
     /**
      * @return Keep portable flag.
      */
-    public boolean keepPortable() {
+    public boolean keepIgniteObject() {
         CacheOperationContext opCtx = operationContextPerCall();
 
-        return opCtx != null && opCtx.isKeepPortable();
+        return opCtx != null && opCtx.isKeepIgniteObject();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
index cec8c53..4818675 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProxyImpl.java
@@ -218,13 +218,13 @@ public class GridCacheProxyImpl<K, V> implements IgniteInternalCache<K, V>, Exte
     }
 
     /** {@inheritDoc} */
-    @Override public <K1, V1> GridCacheProxyImpl<K1, V1> keepPortable() {
-        if (opCtx != null && opCtx.isKeepPortable())
+    @Override public <K1, V1> GridCacheProxyImpl<K1, V1> keepIgniteObject() {
+        if (opCtx != null && opCtx.isKeepIgniteObject())
             return (GridCacheProxyImpl<K1, V1>)this;
         
         return new GridCacheProxyImpl<>((GridCacheContext<K1, V1>)ctx, 
             (GridCacheAdapter<K1, V1>)delegate,
-            opCtx != null ? opCtx.keepPortable() : new CacheOperationContext(false, null, true, null, false));
+            opCtx != null ? opCtx.keepIgniteObject() : new CacheOperationContext(false, null, true, null, false));
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
index 0b2eba0..2867443 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxy.java
@@ -272,6 +272,33 @@ public class IgniteCacheProxy<K, V> extends AsyncSupportAdapter<IgniteCache<K, V
     }
 
     /** {@inheritDoc} */
+    @Override public IgniteCache<K, V> withIgniteObject() {
+        GridCacheGateway<K, V> gate = this.gate;
+
+        CacheOperationContext prev = onEnter(gate, opCtx);
+
+        try {
+            boolean obj = opCtx != null && opCtx.isKeepIgniteObject();
+
+            if (obj)
+                return this;
+
+            CacheOperationContext opCtx0 = opCtx == null ?
+                new CacheOperationContext(false, null, true, null, false) :
+                opCtx.keepIgniteObject();
+
+            return new IgniteCacheProxy<>(ctx,
+                delegate,
+                opCtx0,
+                isAsync(),
+                lock);
+        }
+        finally {
+            onLeave(gate, prev);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteCache<K, V> withNoRetries() {
         GridCacheGateway<K, V> gate = this.gate;
 
@@ -400,7 +427,7 @@ public class IgniteCacheProxy<K, V> extends AsyncSupportAdapter<IgniteCache<K, V
         final CacheQuery<Map.Entry<K,V>> qry;
         final CacheQueryFuture<Map.Entry<K,V>> fut;
 
-        boolean isKeepPortable = opCtx != null && opCtx.isKeepPortable();
+        boolean isKeepPortable = opCtx != null && opCtx.isKeepIgniteObject();
 
         if (filter instanceof ScanQuery) {
             IgniteBiPredicate<K, V> p = ((ScanQuery)filter).getFilter();
@@ -1612,7 +1639,7 @@ public class IgniteCacheProxy<K, V> extends AsyncSupportAdapter<IgniteCache<K, V
      * </ul> <p> For example, if you use {@link Integer} as a key and {@code Value} class as a value (which will be
      * stored in portable format), you should acquire following projection to avoid deserialization:
      * <pre>
-     * IgniteInternalCache<Integer, GridPortableObject> prj = cache.keepPortable();
+     * IgniteInternalCache<Integer, GridPortableObject> prj = cache.keepIgniteObject();
      *
      * // Value is not deserialized and returned in portable format.
      * GridPortableObject po = prj.get(1);
@@ -1624,7 +1651,7 @@ public class IgniteCacheProxy<K, V> extends AsyncSupportAdapter<IgniteCache<K, V
      * @return Projection for portable objects.
      */
     @SuppressWarnings("unchecked")
-    public <K1, V1> IgniteCache<K1, V1> keepPortable() {
+    public <K1, V1> IgniteCache<K1, V1> keepIgniteObjects() {
         GridCacheGateway<K, V> gate = this.gate;
 
         CacheOperationContext prev = onEnter(gate, opCtx);
@@ -1666,7 +1693,7 @@ public class IgniteCacheProxy<K, V> extends AsyncSupportAdapter<IgniteCache<K, V
             CacheOperationContext opCtx0 =
                 new CacheOperationContext(true,
                     opCtx != null ? opCtx.subjectId() : null,
-                    opCtx != null && opCtx.isKeepPortable(),
+                    opCtx != null && opCtx.isKeepIgniteObject(),
                     opCtx != null ? opCtx.expiry() : null,
                     opCtx != null && opCtx.noRetries());
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
index 9972f92..af9a325 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteInternalCache.java
@@ -174,14 +174,14 @@ import java.util.Date;
  * You won't be able to work with deserialized form if class definition for the {@code Value} is not on
  * classpath. Even if you have the class definition, you should always avoid full deserialization if it's not
  * needed for performance reasons. To work with portable format directly you should create special projection
- * using {@link #keepPortable()} method:
+ * using {@link #keepIgniteObject()} method:
  * <pre>
- * IgniteInternalCache<Integer, GridPortableObject> prj = Ignition.grid().cache(null).keepPortable();
+ * IgniteInternalCache<Integer, GridPortableObject> prj = Ignition.grid().cache(null).keepIgniteObject();
  *
  * // Value is not deserialized and returned in portable format.
  * GridPortableObject po = prj.get(1);
  * </pre>
- * See {@link #keepPortable()} method JavaDoc for more details.
+ * See {@link #keepIgniteObject()} method JavaDoc for more details.
  */
 public interface IgniteInternalCache<K, V> extends Iterable<Cache.Entry<K, V>> {
     /**
@@ -237,7 +237,7 @@ public interface IgniteInternalCache<K, V> extends Iterable<Cache.Entry<K, V>> {
      * (which will be stored in portable format), you should acquire following projection
      * to avoid deserialization:
      * <pre>
-     * IgniteInternalCache<Integer, GridPortableObject> prj = cache.keepPortable();
+     * IgniteInternalCache<Integer, GridPortableObject> prj = cache.keepIgniteObject();
      *
      * // Value is not deserialized and returned in portable format.
      * GridPortableObject po = prj.get(1);
@@ -249,7 +249,7 @@ public interface IgniteInternalCache<K, V> extends Iterable<Cache.Entry<K, V>> {
      *
      * @return New internal cache instance for portable objects.
      */
-    public <K1, V1> IgniteInternalCache<K1, V1> keepPortable();
+    public <K1, V1> IgniteInternalCache<K1, V1> keepIgniteObject();
 
     /**
      * Returns {@code true} if this map contains no key-value mappings.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java
index 2a13f90..02ee988 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheIndexedObjectImpl.java
@@ -17,8 +17,6 @@
 
 package org.apache.ignite.internal.processors.cache;
 
-import org.apache.ignite.*;
-
 /**
  * Cache object implementation for classes that support footer injection is their serialized form thus enabling fields
  * search and extraction without necessity to fully deserialize an object.
@@ -55,45 +53,13 @@ public class KeyCacheIndexedObjectImpl extends CacheIndexedObjectImpl implements
     }
 
     /** {@inheritDoc} */
-    @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader ldr) throws IgniteCheckedException {
-        assert val != null || valBytes != null;
-
-        if (val == null)
-            val = ctx.processor().unmarshal(ctx, valBytes, start, len, ldr);
-    }
-
-    /** {@inheritDoc} */
     @Override public byte directType() {
         // refer to GridIoMessageFactory.
-        return 113;
+        return 114;
     }
 
     /** {@inheritDoc} */
     @Override public boolean internal() {
-        assert val != null;
-
-        return val instanceof GridCacheInternal;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int hashCode() {
-        assert val != null;
-
-        return val.hashCode();
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean equals(Object obj) {
-        if (!(obj instanceof KeyCacheIndexedObjectImpl))
-            return false;
-
-        KeyCacheIndexedObjectImpl other = (KeyCacheIndexedObjectImpl)obj;
-
-        return val.equals(other.val);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected boolean keepDeserialized(CacheObjectContext ctx, boolean checkCls) {
-        return true;
+        return false;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
index 22a5287..2b60c82 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java
@@ -967,7 +967,7 @@ public abstract class GridDhtCacheAdapter<K, V> extends GridDistributedCacheAdap
         assert primary || backup;
 
         if (primary && backup)
-            return iterator(map.entries0().iterator(), !ctx.keepPortable());
+            return iterator(map.entries0().iterator(), !ctx.keepIgniteObject());
         else {
             final AffinityTopologyVersion topVer = ctx.affinity().affinityTopologyVersion();
 
@@ -1031,7 +1031,7 @@ public abstract class GridDhtCacheAdapter<K, V> extends GridDistributedCacheAdap
                 }
             };
 
-            return iterator(it, !ctx.keepPortable());
+            return iterator(it, !ctx.keepIgniteObject());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
index d041bb7..1baf121 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
@@ -755,7 +755,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
         IgniteInternalCache<K, V> prj0 = cctx.cache();
 
         if (qry.keepPortable())
-            prj0 = prj0.keepPortable();
+            prj0 = prj0.keepIgniteObject();
 
         final IgniteInternalCache<K, V> prj = prj0;
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
index 8113c4a..1325cb2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
@@ -245,7 +245,7 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
 
             Object storeKey = key.value(cctx.cacheObjectContext(), false);
 
-            if (OptimizedMarshallerUtils.isObjectWithIndexedFieldsOrCollection(storeKey) || convertPortable())
+            if (convertPortable())
                 storeKey = cctx.unwrapIfNeeded(storeKey, false);
 
             if (log.isDebugEnabled())
@@ -499,9 +499,7 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
             if (key instanceof GridCacheInternal)
                 return true;
 
-            if (OptimizedMarshallerUtils.isObjectWithIndexedFieldsOrCollection(key) ||
-                OptimizedMarshallerUtils.isObjectWithIndexedFieldsOrCollection(val) ||
-                convertPortable()) {
+            if (convertPortable()) {
                 key = cctx.unwrapIfNeeded(key, false);
                 val = cctx.unwrapIfNeeded(val, false);
             }
@@ -606,7 +604,7 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
             if (key instanceof GridCacheInternal)
                 return false;
 
-            if (OptimizedMarshallerUtils.isObjectWithIndexedFieldsOrCollection(key) || convertPortable())
+            if (convertPortable())
                 key = cctx.unwrapIfNeeded(key, false);
 
             if (log.isDebugEnabled())
@@ -1075,9 +1073,7 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
 
                         Object v = locStore ? e.getValue() : e.getValue().get1();
 
-                        if (OptimizedMarshallerUtils.isObjectWithIndexedFieldsOrCollection(k) ||
-                            OptimizedMarshallerUtils.isObjectWithIndexedFieldsOrCollection(v) ||
-                            convertPortable()) {
+                        if (convertPortable()) {
                             k = cctx.unwrapIfNeeded(k, false);
                             v = cctx.unwrapIfNeeded(v, false);
                         }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
index 0a61b1a..fdf044a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
@@ -2315,7 +2315,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter
                 /*read through*/cacheCtx.config().isLoadPreviousValue() && !skipStore,
                 /*async*/true,
                 missedForLoad,
-                deserializePortables(cacheCtx),
+                deserializeIgniteObject(cacheCtx),
                 /*skip values*/false,
                 new CI2<KeyCacheObject, Object>() {
                     @Override public void apply(KeyCacheObject key, Object val) {
@@ -3009,10 +3009,10 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter
      * @param cacheCtx Cache context.
      * @return {@code True} if portables should be deserialized, {@code false} otherwise.
      */
-    private boolean deserializePortables(GridCacheContext cacheCtx) {
+    private boolean deserializeIgniteObject(GridCacheContext cacheCtx) {
         CacheOperationContext opCtx = cacheCtx.operationContextPerCall();
 
-        return opCtx == null || !opCtx.isKeepPortable();
+        return opCtx == null || !opCtx.isKeepIgniteObject();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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 2476499..16f7ef8 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
@@ -559,7 +559,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme
         /** {@inheritDoc} */
         @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
             try {
-                toMarshaledFormIfNeeded(ctx);
+                toMarshaledFormIfNeeded();
 
                 if (keepDeserialized(ctx, true)) {
                     ClassLoader ldr = ctx.p2pEnabled() ?
@@ -605,7 +605,7 @@ public class IgniteCacheObjectProcessorImpl extends GridProcessorAdapter impleme
         @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
             try {
                 if (!ctx.processor().immutable(val)) {
-                    toMarshaledFormIfNeeded(ctx);
+                    toMarshaledFormIfNeeded();
 
                     ClassLoader ldr = ctx.p2pEnabled() ?
                         IgniteUtils.detectClassLoader(IgniteUtils.detectClass(val)) : U.gridClassLoader();

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index 3b0cea3..9df5acb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -591,7 +591,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
                     return idx.queryTwoStep(
                         cctx,
                         qry,
-                        cctx.keepPortable());
+                        cctx.keepIgniteObject());
                 }
             });
         }
@@ -764,7 +764,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
             throw new IllegalStateException("Failed to execute query (grid is stopping).");
 
         try {
-            final boolean keepPortable = cctx.keepPortable();
+            final boolean keepPortable = cctx.keepIgniteObject();
 
             return executeQuery(cctx, new IgniteOutClosureX<QueryCursor<List<?>>>() {
                 @Override public QueryCursor<List<?>> applyx() throws IgniteCheckedException {

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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 455e4db..da91b96 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
@@ -757,6 +757,8 @@ public class OptimizedClassDescriptor {
                         "set OptimizedMarshaller.setRequireSerializable() to false " +
                         "(note that performance may degrade if object is not Serializable): " + name);
 
+                idxHandler.enableFieldsIndexingForClass(obj.getClass());
+
                 writeTypeData(out);
 
                 out.writeShort(checksum);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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 4b06a4e..77eb6f3 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
@@ -87,7 +87,7 @@ public class OptimizedMarshaller extends AbstractMarshaller {
     private OptimizedMarshallerIdMapper mapper;
 
     /** */
-    private OptimizedMarshallerProtocolVersion protocolVersion = OptimizedMarshallerProtocolVersion.VER_1_1;
+    private OptimizedMarshallerProtocolVersion protocolVersion = OptimizedMarshallerProtocolVersion.VER_1;
 
     /** */
     private OptimizedMarshallerIndexingHandler idxHandler;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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 420da5d..2ef45e9 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
@@ -261,28 +261,6 @@ public class OptimizedMarshallerUtils {
     }
 
     /**
-     * Checks whether the given object is a wrapper, that contains serialized form of an object with indexed fields, or
-     * {@link Collection} or {@link Map}.
-     *
-     * @param obj Object.
-     * @return {@code true} if all the conditions are met..
-     */
-    public static boolean isObjectWithIndexedFieldsOrCollection(Object obj) {
-        if (obj == null)
-            return false;
-
-        if (obj instanceof CacheIndexedObjectImpl ||
-            obj instanceof Map.Entry ||
-            obj instanceof Collection ||
-            obj instanceof Map ||
-            obj.getClass() == Object[].class)
-            return true;
-
-        return false;
-    }
-
-
-    /**
      * Gets descriptor for provided ID.
      *
      * @param clsMap Class descriptors by class map.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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 40d551c..eabebc6 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
@@ -32,6 +32,7 @@ import java.util.*;
 import java.util.concurrent.*;
 
 import static org.apache.ignite.marshaller.optimized.OptimizedMarshallerUtils.*;
+import static org.apache.ignite.marshaller.optimized.OptimizedObjectOutputStream.*;
 
 /**
  * Optimized object input stream.
@@ -1290,15 +1291,7 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         if (type != SERIALIZABLE && type != MARSHAL_AWARE)
             return false;
 
-        FieldRange range;
-
-        try {
-            range = fieldRange(fieldName, start);
-        }
-        catch (IgniteFieldNotFoundException e) {
-            // Ignore
-            return false;
-        }
+        FieldRange range = fieldRange(fieldName, start);
 
         return range != null && range.start >= 0;
     }
@@ -1351,9 +1344,8 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
      * @param start Object's start offset.
      * @return positive range or {@code null} if the object doesn't have such a field.
      * @throws IOException in case of error.
-     * @throws IgniteFieldNotFoundException In case if there is no such a field.
      */
-    private FieldRange fieldRange(String fieldName, int start) throws IOException, IgniteFieldNotFoundException {
+    private FieldRange fieldRange(String fieldName, int start) throws IOException {
         int pos = start + 1;
 
         int typeId = in.readInt(pos);
@@ -1372,23 +1364,26 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         OptimizedObjectMetadata meta = idxHandler.metaHandler().metadata(typeId);
 
         if (meta == null)
-            // TODO: IGNITE-950 add warning!
             return null;
 
         int end = in.size();
 
-        short footerLen = in.readShort(end - FOOTER_LEN_OFF);
+        short footerLen = in.readShort(end - FOOTER_LENGTH_FIELD_SIZE);
 
         if (footerLen == EMPTY_FOOTER)
-            throw new IgniteFieldNotFoundException("Object doesn't have a field named: " + fieldName);
+            return null;
 
         if (range == null)
             range = new FieldRange();
 
-        // Calculating start footer offset. +2 - skipping length at the beginning
-        pos = (end - footerLen) + 2;
+        // Calculating start footer offset. Skipping length at the beginning
+        pos = (end - footerLen) + FOOTER_LENGTH_FIELD_SIZE;
 
         int fieldIdx = meta.fieldIndex(fieldName);
+
+        if (fieldIdx < 0)
+            return null;
+
         int fieldsCnt = meta.size();
 
         if (fieldIdx >= fieldsCnt)
@@ -1397,7 +1392,7 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         boolean hasHandles = in.readByte(end - FOOTER_HANDLES_FLAG_OFF) == 1;
 
         if (hasHandles) {
-            long fieldInfo = in.readLong(pos + fieldIdx * 8);
+            long fieldInfo = in.readLong(pos + fieldIdx * HANDLE_FOOTER_ELEMENT_SIZE);
 
             boolean isHandle = ((fieldInfo & FOOTER_BODY_IS_HANDLE_MASK) >> FOOTER_BODY_HANDLE_MASK_BIT) == 1;
 
@@ -1414,11 +1409,12 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
             }
         }
         else
-            range.start = in.readInt(pos + fieldIdx * 4) & FOOTER_BODY_OFF_MASK;
+            range.start = in.readInt(pos + fieldIdx * PLAIN_FOOTER_ELEMENT_SIZE) & FOOTER_BODY_OFF_MASK;
 
         if (fieldIdx == 0) {
             if (fieldsCnt > 1) {
-                int nextFieldOff = in.readInt(pos + (fieldIdx + 1) * 4);
+                int nextFieldOff = in.readInt(pos + (fieldIdx + 1) * PLAIN_FOOTER_ELEMENT_SIZE);
+
                 range.len = nextFieldOff - range.start;
             }
             else
@@ -1427,7 +1423,8 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         else if (fieldIdx == fieldsCnt - 1)
             range.len = (end - footerLen) - range.start;
         else {
-            int nextFieldOff = in.readInt(pos + (fieldIdx + 1) * 4);
+            int nextFieldOff = in.readInt(pos + (fieldIdx + 1) * PLAIN_FOOTER_ELEMENT_SIZE);
+
             range.len = nextFieldOff - range.start;
         }
 
@@ -1444,12 +1441,6 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         /** */
         private int len;
 
-        /**
-         * Constructor.
-         */
-        public FieldRange() {
-        }
-
         /** {@inheritDoc} */
         @Override public String toString() {
             return S.toString(FieldRange.class, this);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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
index f55d404..74b6207 100644
--- 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
@@ -56,17 +56,16 @@ public class OptimizedObjectMetadata implements Externalizable {
      * object's serialized form.
      *
      * @param fieldName Field name.
-     * @return Index.
-     * @throws IgniteFieldNotFoundException If object doesn't have such a field.
+     * @return Index or {@code -1} if field index cannot be resolved.
      */
-    public int fieldIndex(String fieldName) throws IgniteFieldNotFoundException {
+    public int fieldIndex(String fieldName) {
         if (indexes == null)
-            throw new IgniteFieldNotFoundException("Object doesn't have field named: " + fieldName);
+            return -1;
 
         FieldInfo info = indexes.get(OptimizedMarshallerUtils.resolveFieldId(fieldName));
 
         if (info == null)
-            throw new IgniteFieldNotFoundException("Object doesn't have field named: " + fieldName);
+            return -1;
 
         return info.index();
     }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/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 a23d529..ea0aef1 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
@@ -57,6 +57,24 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
     /** */
     private static final long longArrOff = UNSAFE.arrayBaseOffset(long[].class);
 
+    /** Footer length field size in output format. */
+    public static final int FOOTER_LENGTH_FIELD_SIZE = 2;
+
+    /** Object hash code field size in output format. */
+    public static final int FOOTER_OBJECT_HASH_CODE_FIELD_SIZE = 4;
+
+    /** Handles indicator field size. */
+    public static final int FOOTER_HANDLES_FIELD_SIZE = 1;
+
+    /** Footer plain overhead size. */
+    public static final int FOOTER_OVERHEAD = 2 * FOOTER_LENGTH_FIELD_SIZE + FOOTER_OBJECT_HASH_CODE_FIELD_SIZE +
+        FOOTER_HANDLES_FIELD_SIZE;
+
+    /** Handle footer element size. */
+    public static final int HANDLE_FOOTER_ELEMENT_SIZE = 8;
+
+    /** Plain footer element size. */
+    public static final int PLAIN_FOOTER_ELEMENT_SIZE = 4;
 
     /** */
     private final GridDataOutput out;
@@ -351,6 +369,8 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
 
         Footer footer = getFooter();
 
+        footer.objectHashCode(obj.hashCode());
+
         if (marshalAwareFooters == null)
             marshalAwareFooters = new Stack<>();
 
@@ -383,8 +403,11 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
 
             out.writeBoolean(hasFooter);
 
-            if (hasFooter)
+            if (hasFooter) {
                 footer = getFooter();
+
+                footer.objectHashCode(obj.hashCode());
+            }
         }
 
         for (int i = 0; i < mtds.size(); i++) {
@@ -1242,6 +1265,9 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
         private int size;
 
         /** */
+        private int objHashCode;
+
+        /** */
         private boolean hasHandles;
 
 
@@ -1275,6 +1301,15 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
         }
 
         /**
+         * Sets object hash code to write.
+         *
+         * @param hashCode Object hash code.
+         */
+        public void objectHashCode(int hashCode) {
+            objHashCode = hashCode;
+        }
+
+        /**
          * Writes footer content to the OutputStream.
          *
          * @throws IOException In case of error.
@@ -1283,9 +1318,13 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
             if (data == null)
                 writeShort(EMPTY_FOOTER);
             else {
-                // +5 - 2 bytes for footer len at the beginning, 2 bytes for footer len at the end, 1 byte for handles
-                // indicator flag.
-                short footerLen = (short)(size * (hasHandles ? 8 : 4) + 5);
+                // OVERHEAD =
+                //      footer len at the beginning,
+                //      object hash code,
+                //      handles indicator flag,
+                //      footer len at the end,
+                short footerLen = (short)(size * (hasHandles ? HANDLE_FOOTER_ELEMENT_SIZE : PLAIN_FOOTER_ELEMENT_SIZE)
+                    + FOOTER_OVERHEAD);
 
                 writeShort(footerLen);
 
@@ -1298,12 +1337,15 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
                         writeInt((int)data[i]);
                 }
 
+                writeInt(objHashCode);
+
                 writeByte(hasHandles ? 1 : 0);
 
                 writeShort(footerLen);
             }
 
             size = 0;
+            objHashCode = 0;
             hasHandles = false;
 
             if (footersPool.size() < MAX_FOOTERS_POOL_SIZE)

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
index 22877df..ccf92b9 100644
--- a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
@@ -37,7 +37,7 @@ public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest
     private static OptimizedMarshallerIndexingHandler idxHandler;
 
     /** */
-    private CacheObjectContext objCtx;
+    private transient CacheObjectContext objCtx;
 
     /** */
     private static final OptimizedMarshallerMetaHandler META_HANDLER = new OptimizedMarshallerMetaHandler() {
@@ -115,10 +115,10 @@ public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest
 
         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, objCtx);
+        // CacheObject extraction.
+        CacheIndexedObject o2 = marsh.readField("o2", arr, 0, arr.length, null, objCtx);
 
-        assertEquals(testObj.o2, o2);
+        assertEquals(testObj.o2, o2.deserialize());
 
         // Add metadata for the enclosed object.
         assertTrue(idxHandler.enableFieldsIndexingForClass(TestObject2.class));
@@ -173,6 +173,37 @@ public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest
         assertEquals(selfLinkObject, selfLinkObject2);
     }
 
+    /**
+     * @throws Exception If failed.
+     */
+    public void testHashCode() throws Exception {
+        OptimizedMarshaller marsh = (OptimizedMarshaller)OptimizedMarshallerExtSelfTest.marsh;
+
+        for (int i = 0; i < 100; i++) {
+            TestMarshalAware ma = new TestMarshalAware(i, "value" + i);
+
+            byte[] valBytes = marsh.marshal(ma);
+
+            CacheIndexedObject obj = new CacheIndexedObjectImpl(objCtx, valBytes, 0, valBytes.length);
+
+            assertEquals(ma.hashCode(), obj.hashCode());
+
+            assertEquals(ma.testObject2.hashCode(), obj.<CacheIndexedObject>field("testObject2").hashCode());
+        }
+
+        for (int i = 0; i < 100; i++) {
+            TestObject to = new TestObject("value" + i, i);
+
+            byte[] valBytes = marsh.marshal(to);
+
+            CacheIndexedObject obj = new CacheIndexedObjectImpl(objCtx, valBytes, 0, valBytes.length);
+
+            assertEquals(to.hashCode(), obj.hashCode());
+
+            assertEquals(to.o2.hashCode(), obj.<CacheIndexedObject>field("o2").hashCode());
+        }
+    }
+
 
     /**
      * @throws Exception In case of error.
@@ -396,6 +427,24 @@ public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest
             aware = reader.readObject("aware");
             testObject2 = reader.readObject("testObject2");
         }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return number * 31 + text.hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            TestMarshalAware that = (TestMarshalAware)o;
+
+            return number == that.number && text.equals(that.text);
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
index b15b6ef..0b6ce37 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteCacheProcessProxy.java
@@ -132,6 +132,11 @@ public class IgniteCacheProcessProxy<K, V> implements IgniteCache<K, V> {
         throw new UnsupportedOperationException("Method should be supported.");
     }
 
+    /** {@inheritDoc} */
+    @Override public IgniteCache<K, V> withIgniteObject() {
+        throw new UnsupportedOperationException("Method should be supported.");
+    }
+
     @Override public IgniteCache<K, V> withNoRetries() {
         throw new UnsupportedOperationException("Method should be supported.");
     }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d9bceb56/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
index 65794da..1c008bb 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
@@ -869,7 +869,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
 
         twoStepQry.pageSize(qry.getPageSize());
 
-        QueryCursorImpl<List<?>> cursor = new QueryCursorImpl<>(queryTwoStep(cctx, twoStepQry, cctx.keepPortable()));
+        QueryCursorImpl<List<?>> cursor = new QueryCursorImpl<>(queryTwoStep(cctx, twoStepQry, cctx.keepIgniteObject()));
 
         cursor.fieldsMeta(meta);