Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-950 5e9a45f0c -> 99c88b7cb


ignite-950: added CacheObject implementations for footer enabled classes, 
injected the implementation in IgniteCacheObjectProcessor


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

Branch: refs/heads/ignite-950
Commit: 99c88b7cbfd55698c88a25b5259714954cd50f7d
Parents: 5e9a45f
Author: Denis Magda <dma...@gridgain.com>
Authored: Wed Jun 17 15:28:27 2015 +0300
Committer: Denis Magda <dma...@gridgain.com>
Committed: Wed Jun 17 15:28:27 2015 +0300

----------------------------------------------------------------------
 .../ignite/codegen/MessageCodeGenerator.java    |   3 +-
 .../communication/GridIoMessageFactory.java     |  10 +-
 .../internal/processors/cache/CacheObject.java  |   2 +
 .../processors/cache/CacheObjectImpl.java       |  22 --
 .../cache/CacheOptimizedObjectImpl.java         | 339 +++++++++++++++++++
 .../cache/KeyCacheOptimizedObjectImpl.java      |  99 ++++++
 .../cacheobject/IgniteCacheObjectProcessor.java |  24 +-
 .../IgniteCacheObjectProcessorImpl.java         | 159 ++++++++-
 .../optimized/OptimizedObjectInputStream.java   |   6 +-
 .../optimized/ext/OptimizedMarshallerExt.java   |  57 +++-
 .../ext/OptimizedObjectInputStreamExt.java      |  16 +-
 .../marshaller/optimized/ext/package-info.java  |   2 +-
 .../ext/OptimizedMarshallerExtSelfTest.java     |  10 +-
 13 files changed, 672 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
----------------------------------------------------------------------
diff --git 
a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
 
b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
index 0540148..4780ee4 100644
--- 
a/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
+++ 
b/modules/codegen/src/main/java/org/apache/ignite/codegen/MessageCodeGenerator.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.codegen;
 
 import org.apache.ignite.internal.*;
+import org.apache.ignite.internal.processors.cache.*;
 import org.apache.ignite.internal.util.typedef.internal.*;
 import org.apache.ignite.lang.*;
 import org.apache.ignite.plugin.extensions.communication.*;
@@ -142,7 +143,7 @@ public class MessageCodeGenerator {
 
         MessageCodeGenerator gen = new MessageCodeGenerator(srcDir);
 
-//        gen.generateAndWrite(DataStreamerEntry.class);
+        gen.generateAndWrite(CacheOptimizedObjectImpl.class);
 
 //        gen.generateAndWrite(GridDistributedLockRequest.class);
 //        gen.generateAndWrite(GridDistributedLockResponse.class);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
index 7fe8da8..4c8fec5 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
@@ -600,7 +600,15 @@ public class GridIoMessageFactory implements 
MessageFactory {
 
                 break;
 
-            // [-3..112] - this
+            case 113:
+                msg = new CacheOptimizedObjectImpl();
+
+                break;
+
+            case 114:
+                msg = new KeyCacheOptimizedObjectImpl();
+
+            // [-3..114] - this
             // [120..123] - DR
             // [-4..-22] - SQL
             default:

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
index 2f77e86..14c6196 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java
@@ -31,6 +31,8 @@ public interface CacheObject extends Message {
     /** */
     public static final byte TYPE_BYTE_ARR = 2;
 
+    public static final byte TYPE_OPTIMIZED = 3;
+
     /**
      * @param ctx Context.
      * @param cpy If {@code true} need to copy value.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/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 49c0262..96603f9 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
@@ -77,7 +77,6 @@ public class CacheObjectImpl extends CacheObjectAdapter {
         catch (IgniteCheckedException e) {
             throw new IgniteException("Failed to unmarshall object.", e);
         }
-
     }
 
     /** {@inheritDoc} */
@@ -104,27 +103,6 @@ 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/99c88b7c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOptimizedObjectImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOptimizedObjectImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOptimizedObjectImpl.java
new file mode 100644
index 0000000..734451e
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheOptimizedObjectImpl.java
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.marshaller.optimized.ext.*;
+import org.apache.ignite.plugin.extensions.communication.*;
+import org.jetbrains.annotations.*;
+
+import java.io.*;
+import java.nio.*;
+
+/**
+ * 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.
+ */
+public class CacheOptimizedObjectImpl extends CacheObjectAdapter {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** */
+    protected int start;
+
+    /** */
+    protected int len;
+
+    /**
+     * For {@link Externalizable}.
+     */
+    public CacheOptimizedObjectImpl() {
+       // No-op
+    }
+
+    /**
+     * Instantiates {@code CacheOptimizedObjectImpl} with object.
+     * @param val Object.
+     */
+    public CacheOptimizedObjectImpl(Object val) {
+        this(val, null, 0, 0);
+    }
+
+    /**
+     * Instantiates {@code CacheOptimizedObjectImpl} with object's serialized 
form.
+     * @param valBytes Object serialized to byte array.
+     * @param start Object's start in the array.
+     * @param len Object's len in the array.
+     */
+    public CacheOptimizedObjectImpl(byte[] valBytes, int start, int len) {
+        this(null, valBytes, start, len);
+    }
+
+    /**
+     * Instantiates {@code CacheOptimizedObjectImpl} with object's serialized 
form and value.
+     * @param val Object.
+     * @param valBytes Object serialized to byte array.
+     */
+    public CacheOptimizedObjectImpl(Object val, byte[] valBytes) {
+        this(val, valBytes, 0, valBytes != null ? valBytes.length : 0);
+    }
+
+    /**
+     * Instantiates {@code CacheOptimizedObjectImpl}.
+     * @param val Object.
+     * @param valBytes Object in a serialized form.
+     * @param start Object's start in the array.
+     * @param len Object's len in the array.
+     */
+    public CacheOptimizedObjectImpl(Object val, byte[] valBytes, int start, 
int len) {
+        assert val != null || (valBytes != null && start >= 0 && len > 0);
+
+        this.val = val;
+        this.valBytes = valBytes;
+        this.start = start;
+        this.len = len;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean 
cpy) {
+        cpy = cpy && needCopy(ctx);
+
+        try {
+            if (cpy) {
+                toMarshaledFormIfNeeded(ctx);
+
+                return (T)ctx.processor().unmarshal(ctx, valBytes,
+                    val == null ? 
ctx.kernalContext().config().getClassLoader() : 
val.getClass().getClassLoader());
+            }
+
+            if (val != null)
+                return (T)val;
+
+            assert valBytes != null;
+
+            Object val = ctx.processor().unmarshal(ctx, valBytes, start, len,
+                ctx.kernalContext().config().getClassLoader());
+
+            if (ctx.storeValue())
+                this.val = val;
+
+            return (T)val;
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException("Failed to unmarshall object.", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] valueBytes(CacheObjectContext ctx) throws 
IgniteCheckedException {
+        toMarshaledFormIfNeeded(ctx);
+
+        if (detached())
+            return valBytes;
+
+        byte[] arr = new byte[len];
+
+        U.arrayCopy(valBytes, start, arr, 0, len);
+
+        return arr;
+    }
+
+    /** {@inheritDoc} */
+    @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+        if (detached())
+            return this;
+
+        return detach();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader 
ldr) throws IgniteCheckedException {
+        assert val != null || valBytes != null;
+
+        if (val == null && ctx.storeValue())
+            val = ctx.processor().unmarshal(ctx, valBytes, ldr);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(CacheObjectContext ctx) throws 
IgniteCheckedException {
+        assert val != null || valBytes != null;
+
+        toMarshaledFormIfNeeded(ctx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte directType() {
+        // refer to GridIoMessageFactory.
+        return 113;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte type() {
+        return TYPE_OPTIMIZED;
+    }
+
+    /**
+     * Checks whether a wrapped object has field with name {@code fieldName}.
+     *
+     * @param fieldName Field name.
+     * @param marsh Marshaller.
+     * @return {@code true} if has.
+     * @throws IgniteCheckedException In case of error.
+     */
+    public boolean hasField(String fieldName, OptimizedMarshallerExt marsh) 
throws IgniteCheckedException {
+        assert valBytes != null;
+
+        return marsh.hasField(fieldName, valBytes, start, len);
+    }
+
+    /**
+     * Searches and returns field if it exists.
+     *
+     * @param fieldName Field name.
+     * @param marsh Marshaller.
+     * @return Field.
+     * @throws IgniteCheckedException In case of error.
+     */
+    public Object field(String fieldName, OptimizedMarshallerExt marsh) throws 
IgniteCheckedException {
+        assert valBytes != null;
+
+        return marsh.readField(fieldName, valBytes, start, len, val != null ?  
val.getClass().getClassLoader() : null);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeExternal(ObjectOutput out) throws IOException {
+        super.writeExternal(out);
+
+        out.writeInt(start);
+        out.writeInt(len);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+        super.readExternal(in);
+
+        start = in.readInt();
+        len = in.readInt();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+        reader.setBuffer(buf);
+
+        if (!reader.beforeMessageRead())
+            return false;
+
+        if (!super.readFrom(buf, reader))
+            return false;
+
+        switch (reader.state()) {
+            case 1:
+                len = reader.readInt("len");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 2:
+                start = reader.readInt("start");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+        writer.setBuffer(buf);
+
+        if (!super.writeTo(buf, writer))
+            return false;
+
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(directType(), fieldsCount()))
+                return false;
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 1:
+                if (!writer.writeInt("len", len))
+                    return false;
+
+                writer.incrementState();
+
+            case 2:
+                if (!writer.writeInt("start", start))
+                    return false;
+
+                writer.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte fieldsCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        assert false;
+
+        return super.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object obj) {
+        assert false;
+
+        return super.equals(obj);
+    }
+
+    /**
+     * Detaches object.
+     *
+     * @return Detached object wrapped by {@code CacheOptimizedObjectImpl}.
+     */
+    protected CacheOptimizedObjectImpl detach() {
+        if (detached())
+            return this;
+
+        byte[] arr = new byte[len];
+
+        U.arrayCopy(valBytes, start, arr, 0, len);
+
+        return new CacheOptimizedObjectImpl(arr, 0, len);
+    }
+
+    /**
+     * Checks whether the object is already detached or not.
+     *
+     * @return {@code true} if detached.
+     */
+    protected boolean detached() {
+        return start == 0 && len == valBytes.length;
+    }
+
+    /**
+     * 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 {
+        if (valBytes == null) {
+            assert val != null;
+
+            valBytes = ctx.processor().marshal(ctx, val);
+
+            start = 0;
+            len = valBytes.length;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheOptimizedObjectImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheOptimizedObjectImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheOptimizedObjectImpl.java
new file mode 100644
index 0000000..8da074e
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheOptimizedObjectImpl.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.jetbrains.annotations.*;
+
+/**
+ * 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.
+ */
+public class KeyCacheOptimizedObjectImpl extends CacheOptimizedObjectImpl 
implements KeyCacheObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     *
+     */
+    public KeyCacheOptimizedObjectImpl() {
+        // No-op
+    }
+
+    /**
+     * @param val Object.
+     * @param valBytes Object in a serialized form.
+     */
+    public KeyCacheOptimizedObjectImpl(Object val, byte[] valBytes) {
+        super(val, valBytes);
+
+        assert val != null;
+    }
+
+    /**
+     * @param val Object.
+     * @param valBytes Object in a serialized form.
+     * @param start Object's start in the array.
+     * @param len Object's len in the array.
+     */
+    public KeyCacheOptimizedObjectImpl(Object val, byte[] valBytes, int start, 
int len) {
+        super(val, valBytes, start, len);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean 
cpy) {
+        assert val != null;
+
+        return (T)val;
+    }
+
+    /** {@inheritDoc} */
+    @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte directType() {
+        // refer to GridIoMessageFactory.
+        return 113;
+    }
+
+    /** {@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 KeyCacheOptimizedObjectImpl))
+            return false;
+
+        KeyCacheOptimizedObjectImpl other = (KeyCacheOptimizedObjectImpl)obj;
+
+        return val.equals(other.val);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/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 6a5f947..1afc2fe 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
@@ -22,6 +22,7 @@ import org.apache.ignite.configuration.*;
 import org.apache.ignite.internal.*;
 import org.apache.ignite.internal.processors.*;
 import org.apache.ignite.internal.processors.cache.*;
+import org.apache.ignite.marshaller.optimized.ext.*;
 import org.jetbrains.annotations.*;
 
 /**
@@ -97,15 +98,16 @@ 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.
+     * Checks whether fields indexing is supported by footer injection into a 
serialized form of the object.
+     * Footer contains information about fields location in the serialized 
form, thus enabling fast queries without
+     * a need to deserialize the object.
+     *
+     * Indexing is enabled with {@link 
OptimizedMarshallerExt#enableFieldsIndexing(Class)}.
      *
      * @param cls Class.
      * @return {@code true} if the footer is supported.
-     * @throws IgniteCheckedException If failed.
      */
-    public boolean footerSupported(Class<?> cls) throws IgniteCheckedException;
+    public boolean isFieldsIndexingSupported(Class<?> cls);
 
     /**
      * @param ctx Cache object context.
@@ -125,6 +127,18 @@ public interface IgniteCacheObjectProcessor extends 
GridProcessor {
     public Object unmarshal(CacheObjectContext ctx, byte[] bytes, ClassLoader 
clsLdr) throws IgniteCheckedException;
 
     /**
+     * @param ctx Context.
+     * @param bytes Bytes.
+     * @param off Offset.
+     * @param len Length.
+     * @param clsLdr Class loader.
+     * @return Unmarshalled object.
+     * @throws IgniteCheckedException If failed.
+     */
+    public Object unmarshal(CacheObjectContext ctx, byte[] bytes, int off, int 
len, ClassLoader clsLdr)
+        throws IgniteCheckedException;
+
+    /**
      * @param ccfg Cache configuration.
      * @return Cache object context.
      * @throws IgniteCheckedException If failed.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/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 7a89598..fbbc514 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
@@ -28,7 +28,6 @@ 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.apache.ignite.marshaller.optimized.ext.*;
 import org.jetbrains.annotations.*;
 
@@ -161,6 +160,23 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
     }
 
     /** {@inheritDoc} */
+    @Override public Object unmarshal(CacheObjectContext ctx, byte[] bytes, 
int off, int len,
+                                      ClassLoader clsLdr) throws 
IgniteCheckedException {
+        if (optMarshExt != null)
+            return optMarshExt.unmarshal(bytes, off, len, clsLdr);
+
+        else if (off > 0 || len != bytes.length) {
+            byte[] arr = new byte[len];
+
+            U.arrayCopy(bytes, off, arr, 0, len);
+
+            bytes = arr;
+        }
+
+        return unmarshal(ctx, bytes, clsLdr);
+    }
+
+    /** {@inheritDoc} */
     @Override @Nullable public KeyCacheObject 
toCacheKeyObject(CacheObjectContext ctx, Object obj, boolean userObj) {
         if (obj instanceof KeyCacheObject)
             return (KeyCacheObject)obj;
@@ -177,9 +193,11 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
     @SuppressWarnings("ExternalizableWithoutPublicNoArgConstructor")
     protected KeyCacheObject toCacheKeyObject0(Object obj, boolean userObj) {
         if (!userObj)
-            return new KeyCacheObjectImpl(obj, null);
+            return isFieldsIndexingSupported(obj.getClass()) ? new 
KeyCacheOptimizedObjectImpl(obj, null) :
+                new KeyCacheObjectImpl(obj, null);
 
-        return new UserKeyCacheObjectImpl(obj);
+        return isFieldsIndexingSupported(obj.getClass()) ? new 
UserKeyCacheOptimizedObjectImpl(obj) :
+            new UserKeyCacheObjectImpl(obj);
     }
 
     /** {@inheritDoc} */
@@ -216,16 +234,16 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
 
             case CacheObject.TYPE_REGULAR:
                 return new CacheObjectImpl(null, bytes);
+
+            case CacheObject.TYPE_OPTIMIZED:
+                return new CacheOptimizedObjectImpl(bytes, 0, bytes.length);
         }
 
         throw new IllegalArgumentException("Invalid object type: " + type);
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override public CacheObject toCacheObject(CacheObjectContext 
ctx,
-        @Nullable Object obj,
-        boolean userObj)
-    {
+    @Nullable @Override public CacheObject toCacheObject(CacheObjectContext 
ctx, @Nullable Object obj, boolean userObj){
         if (obj == null || obj instanceof CacheObject)
             return (CacheObject)obj;
 
@@ -250,9 +268,11 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
         }
 
         if (!userObj)
-            return new CacheObjectImpl(obj, null);
+            return isFieldsIndexingSupported(obj.getClass()) ? new 
CacheOptimizedObjectImpl(obj) :
+                new CacheObjectImpl(obj, null);
 
-        return new UserCacheObjectImpl(obj, null);
+        return isFieldsIndexingSupported(obj.getClass()) ? new 
UserCacheOptimizedObjectImpl(obj, null) :
+            new UserCacheObjectImpl(obj, null);
     }
 
     /** {@inheritDoc} */
@@ -311,17 +331,39 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
 
     /** {@inheritDoc} */
     @Override public Object field(Object obj, String fieldName) {
+        if (obj instanceof CacheOptimizedObjectImpl) {
+            assert optMarshExt != null;
+
+            try {
+                return ((CacheOptimizedObjectImpl)obj).field(fieldName, 
optMarshExt);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
         return null;
     }
 
     /** {@inheritDoc} */
     @Override public boolean hasField(Object obj, String fieldName) {
+        if (obj instanceof CacheOptimizedObjectImpl) {
+            assert optMarshExt != null;
+
+            try {
+                return ((CacheOptimizedObjectImpl)obj).hasField(fieldName, 
optMarshExt);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
         return false;
     }
 
     /** {@inheritDoc} */
-    @Override public boolean footerSupported(Class<?> cls) throws 
IgniteCheckedException {
-        return optMarshExt != null && optMarshExt.metaSupported(cls);
+    @Override public boolean isFieldsIndexingSupported(Class<?> cls) {
+        return optMarshExt != null && optMarshExt.fieldsIndexingEnabled(cls);
     }
 
     /**
@@ -420,6 +462,101 @@ public class IgniteCacheObjectProcessorImpl extends 
GridProcessorAdapter impleme
     }
 
     /**
+     * Wraps value provided by user, must be serialized before stored in cache.
+     * Used by classes that support fields indexing. Refer to {@link 
#isFieldsIndexingSupported(Class)}.
+     */
+    private static class UserCacheOptimizedObjectImpl extends 
CacheOptimizedObjectImpl {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /**
+         *
+         */
+        public UserCacheOptimizedObjectImpl() {
+            //No-op.
+        }
+
+        /**
+         * @param val Value.
+         * @param valBytes Value bytes.
+         */
+        public UserCacheOptimizedObjectImpl(Object val, byte[] valBytes) {
+            super(val, valBytes);
+        }
+
+        /** {@inheritDoc} */
+        @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean 
cpy) {
+            return super.value(ctx, false); // Do not need copy since user 
value is not in cache.
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+            try {
+                toMarshaledFormIfNeeded(ctx);
+
+                if (ctx.storeValue()) {
+                    ClassLoader ldr = ctx.p2pEnabled() ?
+                        IgniteUtils.detectClass(this.val).getClassLoader() : 
val.getClass().getClassLoader();
+
+                    Object val = this.val != null && 
ctx.processor().immutable(this.val) ? this.val :
+                        ctx.processor().unmarshal(ctx, valBytes, start, len, 
ldr);
+
+                    return new CacheOptimizedObjectImpl(val, valBytes, start, 
len);
+                }
+
+                return new CacheOptimizedObjectImpl(null, valBytes, start, 
len);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Failed to marshal object: " + val, 
e);
+            }
+        }
+    }
+
+    /**
+     * Wraps key provided by user, must be serialized before stored in cache.
+     * Used by classes that support fields indexing. Refer to {@link 
#isFieldsIndexingSupported(Class)}.
+     */
+    private static class UserKeyCacheOptimizedObjectImpl extends 
KeyCacheOptimizedObjectImpl {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /**
+         *
+         */
+        public UserKeyCacheOptimizedObjectImpl() {
+            //No-op.
+        }
+
+        /**
+         * @param key Key.
+         */
+        UserKeyCacheOptimizedObjectImpl(Object key) {
+            super(key, null);
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+            try {
+                if (!ctx.processor().immutable(val)) {
+                    toMarshaledFormIfNeeded(ctx);
+
+                    ClassLoader ldr = ctx.p2pEnabled() ?
+                        
IgniteUtils.detectClassLoader(IgniteUtils.detectClass(this.val)) : 
U.gridClassLoader();
+
+                    Object val = ctx.processor().unmarshal(ctx, valBytes, 
start, len, ldr);
+
+                    return new KeyCacheOptimizedObjectImpl(val, valBytes, 
start, len);
+                }
+
+                return new KeyCacheOptimizedObjectImpl(val, valBytes, start, 
len);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Failed to marshal object: " + val, 
e);
+            }
+        }
+    }
+
+    /**
      * Wraps value provided by user, must be copied before stored in cache.
      */
     private static class UserCacheObjectByteArrayImpl extends 
CacheObjectByteArrayImpl {

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/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 7d1cad0..c8a85b2 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
@@ -534,7 +534,7 @@ public class OptimizedObjectInputStream extends 
ObjectInputStream {
             }
         }
 
-        readFooter(cls);
+        skipFooter(cls);
 
         return obj;
     }
@@ -936,12 +936,12 @@ public class OptimizedObjectInputStream extends 
ObjectInputStream {
     }
 
     /**
-     * Reads object footer from the underlying stream.
+     * Skips object footer from the underlying stream.
      *
      * @param cls Class.
      * @throws IOException In case of error.
      */
-    protected void readFooter(Class<?> cls) throws IOException {
+    protected void skipFooter(Class<?> cls) throws IOException {
         // No-op
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/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
index 8636566..ddbb1e5 100644
--- 
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
@@ -63,21 +63,22 @@ public class OptimizedMarshallerExt extends 
OptimizedMarshaller {
     }
 
     /**
-     * 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.
+     * Enables fields indexing for the object of the given {@code cls}.
+     *
+     * If enabled then a footer will be added during marshalling of an object 
of the given {@code cls} 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.
+     * @return {@code true} if fields indexing is enabled.
      * @throws IgniteCheckedException In case of error.
      */
-    public boolean putMetaForClass(Class<?> cls) throws IgniteCheckedException 
{
+    public boolean enableFieldsIndexing(Class<?> cls) throws 
IgniteCheckedException {
         assert metaHandler != null;
 
         try {
             OptimizedClassDescriptor desc = 
OptimizedMarshallerUtils.classDescriptor(clsMap, cls, ctx, mapper);
 
-            if (desc.fields().fieldsIndexingSupported()) {
+            if (desc.fields() != null && 
desc.fields().fieldsIndexingSupported()) {
                 if (metaHandler.metadata(desc.typeId()) != null)
                     return true;
 
@@ -100,17 +101,24 @@ public class OptimizedMarshallerExt extends 
OptimizedMarshaller {
     }
 
     /**
-     * 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.
+     * Checks whether fields indexing is enabled for objects of the given 
{@code cls}.
      *
      * @param cls Class.
-     * @return {@code true} if the metadata exists and the footer will be 
written to the end of Object's serialized
-     * form.
+     * @return {@code true} if fields indexing is enabled.
      */
-    public boolean metaSupported(Class<?> cls) throws IgniteCheckedException {
-        return  metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != 
null;
+    public boolean fieldsIndexingEnabled(Class<?> cls) {
+        if (cls == OptimizedObjectMetadataKey.class)
+            return false;
+
+        try {
+            OptimizedClassDescriptor desc = 
OptimizedMarshallerUtils.classDescriptor(clsMap, cls, ctx, mapper);
+
+            return desc.fields() != null && 
desc.fields().fieldsIndexingSupported() &&
+                metaHandler.metadata(desc.typeId()) != null;
+        }
+        catch (IOException e) {
+            throw new IgniteException("Failed to load class description: " + 
cls);
+        }
     }
 
     /** {@inheritDoc} */
@@ -189,6 +197,21 @@ public class OptimizedMarshallerExt extends 
OptimizedMarshaller {
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Override public <T> T unmarshal(byte[] arr, @Nullable ClassLoader clsLdr) 
throws IgniteCheckedException {
+        return unmarshal(arr, 0, arr.length, clsLdr);
+    }
+
+    /**
+     * Unmarshals object from byte array using given class loader and offset 
with len.
+     *
+     * @param <T> Type of unmarshalled object.
+     * @param arr Byte array.
+     * @param off Object's offset in the array.
+     * @param len Object's length in the array.
+     * @param clsLdr Class loader to use.
+     * @return Unmarshalled object.
+     * @throws IgniteCheckedException If unmarshalling failed.
+     */
+     public <T> T unmarshal(byte[] arr, int off, int len, @Nullable 
ClassLoader clsLdr) throws IgniteCheckedException {
         assert arr != null;
 
         OptimizedObjectInputStreamExt objIn = null;
@@ -198,7 +221,7 @@ public class OptimizedMarshallerExt extends 
OptimizedMarshaller {
 
             objIn.context(clsMap, ctx, mapper, clsLdr != null ? clsLdr : 
dfltClsLdr, metaHandler);
 
-            objIn.in().bytes(arr, arr.length);
+            objIn.in().bytes(arr, off, len);
 
             return (T)objIn.readObject();
         }
@@ -207,8 +230,8 @@ public class OptimizedMarshallerExt extends 
OptimizedMarshaller {
         }
         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);
+                                                 "(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/99c88b7c/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
index e3af580..977a988 100644
--- 
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
@@ -22,11 +22,10 @@ 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.*;
+import static 
org.apache.ignite.marshaller.optimized.ext.OptimizedMarshallerExt.*;
 
 
 /**
@@ -55,7 +54,7 @@ public class OptimizedObjectInputStreamExt extends 
OptimizedObjectInputStream {
     }
 
     /** {@inheritDoc} */
-    @Override protected void readFooter(Class<?> cls) throws IOException {
+    @Override protected void skipFooter(Class<?> cls) throws IOException {
         if (metaHandler.metadata(resolveTypeId(cls.getName(), mapper)) != 
null) {
             int footerLen = in.readInt();
 
@@ -116,10 +115,9 @@ public class OptimizedObjectInputStreamExt extends 
OptimizedObjectInputStream {
         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));
-            }
+            if (in.readByte() == SERIALIZABLE && 
metaHandler.metadata(in.readInt()) != null)
+                //Do we need to make a copy of array?
+                field = (F)new CacheOptimizedObjectImpl(in.array(), 
range.start, range.len);
             else {
                 in.position(range.start);
                 field = (F)readObject();
@@ -179,9 +177,7 @@ public class OptimizedObjectInputStreamExt extends 
OptimizedObjectInputStream {
                 //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;
+                return new FieldRange(fieldOff, info.len == VARIABLE_LEN ? 
in.readShort() : info.len);
             }
             else
                 fieldOff += info.len == VARIABLE_LEN ? in.readShort() : 
info.len;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/99c88b7c/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
index 294ef7f..84d1ce3 100644
--- 
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
@@ -16,6 +16,6 @@
  */
 /**
  * <!-- Package description. -->
- * Contains <b>extended</b> Optimized marshaller.
+ * Contains <b>extended</b> version of 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/99c88b7c/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
index d663c55..9887b0b 100644
--- 
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
@@ -22,8 +22,6 @@ 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.
  */
@@ -40,7 +38,7 @@ public class OptimizedMarshallerExtSelfTest extends 
OptimizedMarshallerSelfTest
     public void testHasField() throws Exception {
         OptimizedMarshallerExt marsh = 
(OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
 
-        assertTrue(marsh.putMetaForClass(TestObject.class));
+        assertTrue(marsh.enableFieldsIndexing(TestObject.class));
 
         TestObject testObj = new TestObject("World", 50);
 
@@ -58,7 +56,7 @@ public class OptimizedMarshallerExtSelfTest extends 
OptimizedMarshallerSelfTest
     public void testReadField() throws Exception {
         OptimizedMarshallerExt marsh = 
(OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
 
-        assertTrue(marsh.putMetaForClass(TestObject.class));
+        assertTrue(marsh.enableFieldsIndexing(TestObject.class));
 
         TestObject testObj = new TestObject("World", 50);
 
@@ -76,12 +74,12 @@ public class OptimizedMarshallerExtSelfTest extends 
OptimizedMarshallerSelfTest
         assertEquals(testObj.o2, o2);
 
         // Add metadata for the enclosed object.
-        assertTrue(marsh.putMetaForClass(TestObject2.class));
+        assertTrue(marsh.enableFieldsIndexing(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);
+        CacheOptimizedObjectImpl cacheObject = marsh.readField("o2", arr, 0, 
arr.length, null);
 
         arr = cacheObject.valueBytes(null);
 


Reply via email to