You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/05/10 14:40:42 UTC

[01/13] ignite git commit: IGNITE-5116: Fixed stale DML plan caching in DmlStatementsProcessor.

Repository: ignite
Updated Branches:
  refs/heads/ignite-5009 61021b109 -> 689bdf69b


IGNITE-5116: Fixed stale DML plan caching in DmlStatementsProcessor.


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

Branch: refs/heads/ignite-5009
Commit: cc2a6badb4b3b5dc0e8b3247ddead2f6374bd2e4
Parents: 1af98e9
Author: Alexander Paschenko <al...@gmail.com>
Authored: Fri May 5 14:39:37 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Fri May 5 14:39:37 2017 +0300

----------------------------------------------------------------------
 .../query/h2/DmlStatementsProcessor.java        |  9 ++++++++
 .../processors/query/h2/IgniteH2Indexing.java   |  6 ++++--
 ...niteCacheAbstractInsertSqlQuerySelfTest.java |  3 ++-
 .../IgniteCacheInsertSqlQuerySelfTest.java      | 22 ++++++++++++++++++++
 4 files changed, 37 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/cc2a6bad/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
index 4194bc7..d4109f3 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
@@ -120,6 +120,15 @@ public class DmlStatementsProcessor {
     }
 
     /**
+     * Handle cache stop.
+     *
+     * @param spaceName Cache name.
+     */
+    public void onCacheStop(String spaceName) {
+        planCache.remove(spaceName);
+    }
+
+    /**
      * Execute DML statement, possibly with few re-attempts in case of concurrent data modifications.
      *
      * @param spaceName Space name.

http://git-wip-us.apache.org/repos/asf/ignite/blob/cc2a6bad/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 f7466a8..d62d7d8 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
@@ -393,7 +393,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
     protected volatile GridKernalContext ctx;
 
     /** */
-    private final DmlStatementsProcessor dmlProc = new DmlStatementsProcessor();
+    private DmlStatementsProcessor dmlProc;
 
     /** */
     private DdlStatementsProcessor ddlProc;
@@ -1737,7 +1737,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
             cancel = new GridQueryCancel();
 
         QueryCursorImpl<List<?>> cursor = new QueryCursorImpl<>(
-            runQueryTwoStep(cctx, twoStepQry, cctx.keepBinary(), enforceJoinOrder, qry.getTimeout(), cancel, 
+            runQueryTwoStep(cctx, twoStepQry, cctx.keepBinary(), enforceJoinOrder, qry.getTimeout(), cancel,
                     qry.getArgs(), qry.getPartitions()),
             cancel);
 
@@ -2320,6 +2320,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
                 }
             }, CLEANUP_STMT_CACHE_PERIOD, CLEANUP_STMT_CACHE_PERIOD);
 
+            dmlProc = new DmlStatementsProcessor();
             ddlProc = new DdlStatementsProcessor();
 
             dmlProc.start(ctx, this);
@@ -2538,6 +2539,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
         if (rmv != null) {
             space2schema.remove(emptyIfNull(rmv.spaceName));
             mapQryExec.onCacheStop(spaceName);
+            dmlProc.onCacheStop(spaceName);
 
             rmv.onDrop();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/cc2a6bad/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractInsertSqlQuerySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractInsertSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractInsertSqlQuerySelfTest.java
index 9dc982c..929f535 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractInsertSqlQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractInsertSqlQuerySelfTest.java
@@ -244,6 +244,7 @@ public abstract class IgniteCacheAbstractInsertSqlQuerySelfTest extends GridComm
         ignite(0).cache("K2P").clear();
         ignite(0).cache("K22P").clear();
         ignite(0).cache("I2I").clear();
+        ignite(0).cache("I2AT").clear();
 
         super.afterTest();
     }
@@ -295,7 +296,7 @@ public abstract class IgniteCacheAbstractInsertSqlQuerySelfTest extends GridComm
      * @param idxTypes Indexed types.
      * @return Cache configuration.
      */
-    private static CacheConfiguration cacheConfig(String name, boolean partitioned, boolean escapeSql, Class<?>... idxTypes) {
+    static CacheConfiguration cacheConfig(String name, boolean partitioned, boolean escapeSql, Class<?>... idxTypes) {
         return new CacheConfiguration(DEFAULT_CACHE_NAME)
             .setName(name)
             .setCacheMode(partitioned ? CacheMode.PARTITIONED : CacheMode.REPLICATED)

http://git-wip-us.apache.org/repos/asf/ignite/blob/cc2a6bad/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
index 27f9569..6bbd7e1 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheInsertSqlQuerySelfTest.java
@@ -202,4 +202,26 @@ public class IgniteCacheInsertSqlQuerySelfTest extends IgniteCacheAbstractInsert
 
         assertEquals(resInner, res.innerTypeCol);
     }
+
+    /** */
+    public void testCacheRestartHandling() {
+        IgniteCache<Integer, IgniteCacheUpdateSqlQuerySelfTest.AllTypes> p = ignite(0).cache("I2AT");
+
+        p.query(new SqlFieldsQuery("insert into AllTypes(_key, _val) values (1, ?)")
+            .setArgs(new IgniteCacheUpdateSqlQuerySelfTest.AllTypes(1L)));
+
+        p.destroy();
+
+        p = ignite(0).getOrCreateCache(cacheConfig("I2AT", true, false, Integer.class,
+            IgniteCacheUpdateSqlQuerySelfTest.AllTypes.class));
+
+        p.query(new SqlFieldsQuery("insert into AllTypes(_key, _val, dateCol) values (1, ?, null)")
+            .setArgs(new IgniteCacheUpdateSqlQuerySelfTest.AllTypes(1L)));
+
+        IgniteCacheUpdateSqlQuerySelfTest.AllTypes exp = new IgniteCacheUpdateSqlQuerySelfTest.AllTypes(1L);
+
+        exp.dateCol = null;
+
+        assertEquals(exp, p.get(1));
+    }
 }


[08/13] ignite git commit: master - minor fix for subqueries with aggregates

Posted by sb...@apache.org.
master - minor fix for subqueries with aggregates


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

Branch: refs/heads/ignite-5009
Commit: b039d05a34d8970ee3cbee5cf98ad9e5369772d2
Parents: d10091d
Author: Sergi Vladykin <se...@gmail.com>
Authored: Tue May 9 18:17:40 2017 +0300
Committer: Sergi Vladykin <se...@gmail.com>
Committed: Tue May 9 18:17:40 2017 +0300

----------------------------------------------------------------------
 .../internal/processors/query/h2/sql/GridSqlQuerySplitter.java     | 2 +-
 .../internal/processors/query/IgniteSqlSplitterSelfTest.java       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b039d05a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
index 2bac505..26c6b08 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
@@ -1743,7 +1743,7 @@ public class GridSqlQuerySplitter {
 
         // If in SELECT clause we have a subquery expression with aggregate,
         // we should not split it. Run the whole subquery on MAP stage.
-        if (el instanceof GridSqlQuery)
+        if (el instanceof GridSqlSubquery)
             return false;
 
         for (int i = 0; i < el.size(); i++) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/b039d05a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
index 34101d2..ad1c8b8 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
@@ -306,7 +306,7 @@ public class IgniteSqlSplitterSelfTest extends GridCommonAbstractTest {
             c1.put(new AffinityKey<>(2, orgId), new Person2(orgId, "Another Vasya"));
 
             List<List<?>> rs = c1.query(new SqlFieldsQuery("select name, " +
-                "(select count(1) from Person2 q where q.orgId = p.orgId) " +
+                "select count(1) from Person2 q where q.orgId = p.orgId " +
                 "from Person2 p order by name desc")).getAll();
 
             assertEquals(2, rs.size());


[02/13] ignite git commit: IGNITE-5169: ODBC: reworked handshake semantics to support JDBC driver integration. This closes #1908.

Posted by sb...@apache.org.
IGNITE-5169: ODBC: reworked handshake semantics to support JDBC driver integration. This closes #1908.


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

Branch: refs/heads/ignite-5009
Commit: dddc6d4a4719beaa3d73a62a8b91ee0a51c5392d
Parents: cc2a6ba
Author: devozerov <vo...@gridgain.com>
Authored: Fri May 5 16:57:24 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Fri May 5 16:57:24 2017 +0300

----------------------------------------------------------------------
 .../processors/odbc/OdbcNioListener.java        | 112 +++++++++++++--
 .../internal/processors/odbc/OdbcUtils.java     |   3 -
 .../odbc/SqlListenerHandshakeRequest.java       |  83 -----------
 .../odbc/SqlListenerHandshakeResult.java        |  73 ----------
 .../odbc/SqlListenerProtocolVersion.java        | 110 +++++++++------
 .../processors/odbc/odbc/OdbcMessageParser.java |  43 ------
 .../odbc/odbc/OdbcRequestHandler.java           |  65 +++------
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   1 +
 .../project/vs/odbc-test.vcxproj.filters        |   4 +
 .../cpp/odbc-test/src/configuration_test.cpp    |  39 +++++-
 .../cpp/odbc-test/src/queries_test.cpp          |   4 +-
 .../cpp/odbc/include/ignite/odbc/message.h      |  45 +++---
 .../odbc/include/ignite/odbc/protocol_version.h | 101 ++++++++------
 .../src/system/ui/dsn_configuration_window.cpp  |  10 +-
 modules/platforms/cpp/odbc/src/connection.cpp   |  35 ++---
 .../platforms/cpp/odbc/src/protocol_version.cpp | 136 ++++++++++++-------
 16 files changed, 424 insertions(+), 440 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java
index 423c413..cdb3de3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcNioListener.java
@@ -19,6 +19,11 @@ package org.apache.ignite.internal.processors.odbc;
 
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.binary.BinaryReaderExImpl;
+import org.apache.ignite.internal.binary.BinaryWriterExImpl;
+import org.apache.ignite.internal.binary.streams.BinaryHeapInputStream;
+import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream;
+import org.apache.ignite.internal.binary.streams.BinaryInputStream;
 import org.apache.ignite.internal.processors.odbc.odbc.OdbcMessageParser;
 import org.apache.ignite.internal.processors.odbc.odbc.OdbcRequestHandler;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
@@ -27,12 +32,20 @@ import org.apache.ignite.internal.util.nio.GridNioSession;
 import org.apache.ignite.internal.util.nio.GridNioSessionMetaKey;
 import org.jetbrains.annotations.Nullable;
 
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * ODBC message listener.
  */
 public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> {
+    /** Current version. */
+    private static final SqlListenerProtocolVersion CURRENT_VER = SqlListenerProtocolVersion.create(2, 1, 0);
+
+    /** Supported versions. */
+    private static final Set<SqlListenerProtocolVersion> SUPPORTED_VERS = new HashSet<>();
+
     /** Connection-related metadata key. */
     private static final int CONN_CTX_META_KEY = GridNioSessionMetaKey.nextUniqueKey();
 
@@ -51,6 +64,10 @@ public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> {
     /** Logger. */
     private final IgniteLogger log;
 
+    static {
+        SUPPORTED_VERS.add(CURRENT_VER);
+    }
+
     /**
      * Constructor.
      *
@@ -70,11 +87,6 @@ public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> {
     @Override public void onConnected(GridNioSession ses) {
         if (log.isDebugEnabled())
             log.debug("SQL client connected: " + ses.remoteAddress());
-
-        OdbcRequestHandler handler = new OdbcRequestHandler(ctx, busyLock, maxCursors);
-        OdbcMessageParser parser = new OdbcMessageParser(ctx);
-
-        ses.addMeta(CONN_CTX_META_KEY, new SqlListenerConnectionContext(handler, parser));
     }
 
     /** {@inheritDoc} */
@@ -91,11 +103,15 @@ public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> {
     @Override public void onMessage(GridNioSession ses, byte[] msg) {
         assert msg != null;
 
-        SqlListenerConnectionContext connData = ses.meta(CONN_CTX_META_KEY);
+        SqlListenerConnectionContext connCtx = ses.meta(CONN_CTX_META_KEY);
+
+        if (connCtx == null) {
+            onHandshake(ses, msg);
 
-        assert connData != null;
+            return;
+        }
 
-        SqlListenerMessageParser parser = connData.parser();
+        SqlListenerMessageParser parser = connCtx.parser();
 
         SqlListenerRequest req;
 
@@ -124,7 +140,7 @@ public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> {
                     ", req=" + req + ']');
             }
 
-            SqlListenerRequestHandler handler = connData.handler();
+            SqlListenerRequestHandler handler = connCtx.handler();
 
             SqlListenerResponse resp = handler.handle(req);
 
@@ -145,4 +161,82 @@ public class OdbcNioListener extends GridNioServerListenerAdapter<byte[]> {
             ses.send(parser.encode(new SqlListenerResponse(SqlListenerResponse.STATUS_FAILED, e.toString())));
         }
     }
+
+    /**
+     * Perform handshake.
+     *
+     * @param ses Session.
+     * @param msg Message bytes.
+     */
+    private void onHandshake(GridNioSession ses, byte[] msg) {
+        BinaryInputStream stream = new BinaryHeapInputStream(msg);
+
+        BinaryReaderExImpl reader = new BinaryReaderExImpl(null, stream, null, true);
+
+        byte cmd = reader.readByte();
+
+        if (cmd != SqlListenerRequest.HANDSHAKE) {
+            log.error("Unexpected SQL client request (will close session): " + ses.remoteAddress());
+
+            ses.close();
+
+            return;
+        }
+
+        short verMajor = reader.readShort();
+        short verMinor = reader.readShort();
+        short verMaintenance = reader.readShort();
+
+        SqlListenerProtocolVersion ver = SqlListenerProtocolVersion.create(verMajor, verMinor, verMaintenance);
+
+        String errMsg = null;
+
+        if (SUPPORTED_VERS.contains(ver)) {
+            // Prepare context.
+            SqlListenerConnectionContext connCtx = prepareContext(ver, reader);
+
+            ses.addMeta(CONN_CTX_META_KEY, connCtx);
+        }
+        else {
+            log.warning("Unsupported version: " + ver.toString());
+
+            errMsg = "Unsupported version.";
+        }
+
+        // Send response.
+        BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(8), null, null);
+
+        if (errMsg == null) {
+            writer.writeBoolean(true);
+        }
+        else {
+            writer.writeBoolean(false);
+            writer.writeShort(CURRENT_VER.major());
+            writer.writeShort(CURRENT_VER.minor());
+            writer.writeShort(CURRENT_VER.maintenance());
+            writer.doWriteString(errMsg);
+        }
+
+        ses.send(writer.array());
+    }
+
+    /**
+     * Prepare context.
+     *
+     * @param ver Version.
+     * @param reader Reader.
+     * @return Context.
+     */
+    private SqlListenerConnectionContext prepareContext(SqlListenerProtocolVersion ver, BinaryReaderExImpl reader) {
+        // TODO: Switch between ODBC and JDBC.
+        boolean distributedJoins = reader.readBoolean();
+        boolean enforceJoinOrder = reader.readBoolean();
+
+        OdbcRequestHandler handler =
+            new OdbcRequestHandler(ctx, busyLock, maxCursors, distributedJoins, enforceJoinOrder);
+
+        OdbcMessageParser parser = new OdbcMessageParser(ctx);
+
+        return new SqlListenerConnectionContext(handler, parser);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
index da56813..4b046e8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/OdbcUtils.java
@@ -23,9 +23,6 @@ import org.apache.ignite.IgniteException;
  * Various ODBC utility methods.
  */
 public class OdbcUtils {
-    /** Latest version. */
-    public static final SqlListenerProtocolVersion VER_LATEST = SqlListenerProtocolVersion.VER_2_0_0;
-
     /**
      * Add quotation marks at the beginning and end of the string.
      *

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeRequest.java
deleted file mode 100644
index 09ac05a..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeRequest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.processors.odbc;
-
-import org.apache.ignite.internal.util.typedef.internal.S;
-
-/**
- * ODBC handshake request.
- */
-public class SqlListenerHandshakeRequest extends SqlListenerRequest {
-    /** Protocol version. */
-    private final SqlListenerProtocolVersion ver;
-
-    /** Distributed joins flag. */
-    private boolean distributedJoins = false;
-
-    /** Enforce join order flag. */
-    private boolean enforceJoinOrder = false;
-
-    /**
-     * @param ver Long value for protocol version.
-     */
-    public SqlListenerHandshakeRequest(long ver) {
-        super(HANDSHAKE);
-
-        this.ver = SqlListenerProtocolVersion.fromLong(ver);
-    }
-
-    /**
-     * @return Protocol version.
-     */
-    public SqlListenerProtocolVersion version() {
-        return ver;
-    }
-
-    /**
-     * @return Distributed joins flag.
-     */
-    public boolean distributedJoins() {
-        return distributedJoins;
-    }
-
-    /**
-     * @param distributedJoins Distributed joins flag.
-     */
-    public void distributedJoins(boolean distributedJoins) {
-        this.distributedJoins = distributedJoins;
-    }
-
-    /**
-     * @return Enforce join order flag.
-     */
-    public boolean enforceJoinOrder() {
-        return enforceJoinOrder;
-    }
-
-    /**
-     * @param enforceJoinOrder Enforce join order flag.
-     */
-    public void enforceJoinOrder(boolean enforceJoinOrder) {
-        this.enforceJoinOrder = enforceJoinOrder;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(SqlListenerHandshakeRequest.class, this);
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeResult.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeResult.java
deleted file mode 100644
index ca8b629..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerHandshakeResult.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.processors.odbc;
-
-import org.apache.ignite.internal.util.typedef.internal.S;
-
-/**
- * ODBC handshake result.
- */
-public class SqlListenerHandshakeResult {
-    /** Handshake accepted. */
-    private final boolean accepted;
-
-    /** Apache Ignite version when protocol version has been introduced. */
-    private final String protoVerSince;
-
-    /** Current Apache Ignite version. */
-    private final String curVer;
-
-    /**
-     * Constructor.
-     *
-     * @param accepted Indicates whether handshake accepted or not.
-     * @param protoVerSince Apache Ignite version when protocol version has been introduced.
-     * @param curVer Current Apache Ignite version.
-     */
-    public SqlListenerHandshakeResult(boolean accepted, String protoVerSince, String curVer) {
-        this.accepted = accepted;
-        this.protoVerSince = protoVerSince;
-        this.curVer = curVer;
-    }
-
-    /**
-     * @return Query ID.
-     */
-    public boolean accepted() {
-        return accepted;
-    }
-
-    /**
-     * @return Apache Ignite version when protocol version has been introduced.
-     */
-    public String protocolVersionSince() {
-        return protoVerSince;
-    }
-
-    /**
-     * @return Current Apache Ignite version.
-     */
-    public String currentVersion() {
-        return curVer;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return S.toString(SqlListenerHandshakeResult.class, this);
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerProtocolVersion.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerProtocolVersion.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerProtocolVersion.java
index 62e07ee..690822b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerProtocolVersion.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlListenerProtocolVersion.java
@@ -17,72 +17,100 @@
 
 package org.apache.ignite.internal.processors.odbc;
 
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.NotNull;
+
 /**
  * SQL listener protocol version.
  */
-public enum SqlListenerProtocolVersion {
-    /** Version 2.0.0. */
-    VER_2_0_0(makeVersion(2, 0, 0), "2.0.0"),
-
-    /** Unknown version. */
-    UNKNOWN(Long.MIN_VALUE, "UNKNOWN");
-
-    /** Mask to get 2 lowest bytes of the value and cast to long. */
-    private static final long LONG_MASK = 0x000000000000FFFFL;
+public class SqlListenerProtocolVersion implements Comparable<SqlListenerProtocolVersion> {
+    /** Major part. */
+    private final short major;
 
-    /** Long value for version. */
-    private final long longVal;
+    /** Minor part. */
+    private final short minor;
 
-    /** Since string. */
-    private final String since;
+    /** Maintenance part. */
+    private final short maintenance;
 
     /**
-     * Constructor.
+     * Create version.
      *
-     * @param longVal Long value.
-     * @param since Since string.
+     * @param major Major part.
+     * @param minor Minor part.
+     * @param maintenance Maintenance part.
+     * @return Version.
      */
-    SqlListenerProtocolVersion(long longVal, String since) {
-        this.longVal = longVal;
-        this.since = since;
+    public static SqlListenerProtocolVersion create(int major, int minor, int maintenance) {
+        return new SqlListenerProtocolVersion((short)major, (short)minor, (short)maintenance);
     }
 
     /**
-     * Make long value for the version.
+     * Constructor.
      *
-     * @param major Major version.
-     * @param minor Minor version.
-     * @param maintenance Maintenance version.
-     * @return Long value for the version.
+     * @param major Major part.
+     * @param minor Minor part.
+     * @param maintenance Maintenance part.
      */
-    private static long makeVersion(int major, int minor, int maintenance) {
-        return ((major & LONG_MASK) << 48) | ((minor & LONG_MASK) << 32) | ((maintenance & LONG_MASK) << 16);
+    private SqlListenerProtocolVersion(short major, short minor, short maintenance) {
+        this.major = major;
+        this.minor = minor;
+        this.maintenance = maintenance;
     }
 
     /**
-     * @param longVal Long value.
-     * @return Protocol version.
+     * @return Major part.
      */
-    public static SqlListenerProtocolVersion fromLong(long longVal) {
-        for (SqlListenerProtocolVersion ver : SqlListenerProtocolVersion.values()) {
-            if (ver.longValue() == longVal)
-                return ver;
-        }
-
-        return UNKNOWN;
+    public short major() {
+        return major;
     }
 
     /**
-     * @return Long value.
+     * @return Minor part.
      */
-    public long longValue() {
-        return longVal;
+    public short minor() {
+        return minor;
     }
 
     /**
-     * @return Ignite version when introduced.
+     * @return Maintenance part.
      */
-    public String since() {
-        return since;
+    public short maintenance() {
+        return maintenance;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int compareTo(@NotNull SqlListenerProtocolVersion other) {
+        int res = major - other.major;
+
+        if (res == 0)
+            res = minor - other.minor;
+
+        if (res == 0)
+            res = maintenance - other.maintenance;
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return 31 * (31 * major + minor) + maintenance;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object obj) {
+        if (obj != null && obj instanceof SqlListenerProtocolVersion) {
+            SqlListenerProtocolVersion other = (SqlListenerProtocolVersion)obj;
+
+            return F.eq(major, other.major) && F.eq(minor, other.minor) && F.eq(maintenance, other.maintenance);
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(SqlListenerProtocolVersion.class, this);
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java
index 37fe3bf..af595b9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcMessageParser.java
@@ -27,8 +27,6 @@ import org.apache.ignite.internal.binary.streams.BinaryHeapInputStream;
 import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream;
 import org.apache.ignite.internal.binary.streams.BinaryInputStream;
 import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
-import org.apache.ignite.internal.processors.odbc.SqlListenerHandshakeRequest;
-import org.apache.ignite.internal.processors.odbc.SqlListenerHandshakeResult;
 import org.apache.ignite.internal.processors.odbc.OdbcQueryGetColumnsMetaRequest;
 import org.apache.ignite.internal.processors.odbc.OdbcQueryGetColumnsMetaResult;
 import org.apache.ignite.internal.processors.odbc.OdbcQueryGetParamsMetaRequest;
@@ -62,9 +60,6 @@ public class OdbcMessageParser implements SqlListenerMessageParser {
     /** Logger. */
     private final IgniteLogger log;
 
-    /** Protocol version confirmation flag. */
-    private boolean verConfirmed = false;
-
     /**
      * @param ctx Context.
      */
@@ -86,25 +81,6 @@ public class OdbcMessageParser implements SqlListenerMessageParser {
 
         byte cmd = reader.readByte();
 
-        // This is a special case because we can not decode protocol messages until
-        // we has not confirmed that the remote client uses the same protocol version.
-        if (!verConfirmed) {
-            if (cmd == SqlListenerRequest.HANDSHAKE)
-            {
-                long longVersion = reader.readLong();
-
-                SqlListenerHandshakeRequest res = new SqlListenerHandshakeRequest(longVersion);
-
-                res.distributedJoins(reader.readBoolean());
-                res.enforceJoinOrder(reader.readBoolean());
-
-                return res;
-            }
-            else
-                throw new IgniteException("Unexpected ODBC command " +
-                        "(first message is not a handshake request): [cmd=" + cmd + ']');
-        }
-
         SqlListenerRequest res;
 
         switch (cmd) {
@@ -197,25 +173,6 @@ public class OdbcMessageParser implements SqlListenerMessageParser {
 
         if (res0 == null)
             return writer.array();
-        if (res0 instanceof SqlListenerHandshakeResult) {
-            SqlListenerHandshakeResult res = (SqlListenerHandshakeResult) res0;
-
-            if (log.isDebugEnabled())
-                log.debug("Handshake result: " + (res.accepted() ? "accepted" : "rejected"));
-
-            verConfirmed = res.accepted();
-
-            if (res.accepted()) {
-                verConfirmed = true;
-
-                writer.writeBoolean(true);
-            }
-            else {
-                writer.writeBoolean(false);
-                writer.writeString(res.protocolVersionSince());
-                writer.writeString(res.currentVersion());
-            }
-        }
         else if (res0 instanceof SqlListenerQueryExecuteResult) {
             SqlListenerQueryExecuteResult res = (SqlListenerQueryExecuteResult) res0;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
index 815f650..eabc486 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
@@ -24,8 +24,6 @@ import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.binary.GridBinaryMarshaller;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
-import org.apache.ignite.internal.processors.odbc.SqlListenerHandshakeRequest;
-import org.apache.ignite.internal.processors.odbc.SqlListenerHandshakeResult;
 import org.apache.ignite.internal.processors.odbc.OdbcQueryGetColumnsMetaRequest;
 import org.apache.ignite.internal.processors.odbc.OdbcQueryGetColumnsMetaResult;
 import org.apache.ignite.internal.processors.odbc.OdbcQueryGetParamsMetaRequest;
@@ -35,7 +33,6 @@ import org.apache.ignite.internal.processors.odbc.OdbcQueryGetTablesMetaResult;
 import org.apache.ignite.internal.processors.odbc.OdbcTableMeta;
 import org.apache.ignite.internal.processors.odbc.OdbcUtils;
 import org.apache.ignite.internal.processors.odbc.SqlListenerColumnMeta;
-import org.apache.ignite.internal.processors.odbc.SqlListenerProtocolVersion;
 import org.apache.ignite.internal.processors.odbc.SqlListenerQueryCloseRequest;
 import org.apache.ignite.internal.processors.odbc.SqlListenerQueryCloseResult;
 import org.apache.ignite.internal.processors.odbc.SqlListenerQueryExecuteRequest;
@@ -52,16 +49,24 @@ import org.apache.ignite.internal.util.GridSpinBusyLock;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
-import org.apache.ignite.lang.IgniteProductVersion;
 
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
 import java.sql.Types;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 
-import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.*;
+import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.META_COLS;
+import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.META_PARAMS;
+import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.META_TBLS;
+import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.QRY_CLOSE;
+import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.QRY_EXEC;
+import static org.apache.ignite.internal.processors.odbc.SqlListenerRequest.QRY_FETCH;
 
 /**
  * SQL query handler.
@@ -86,10 +91,10 @@ public class OdbcRequestHandler implements SqlListenerRequestHandler {
     private final ConcurrentHashMap<Long, IgniteBiTuple<QueryCursor, Iterator>> qryCursors = new ConcurrentHashMap<>();
 
     /** Distributed joins flag. */
-    private boolean distributedJoins = false;
+    private final boolean distributedJoins;
 
     /** Enforce join order flag. */
-    private boolean enforceJoinOrder = false;
+    private final boolean enforceJoinOrder;
 
     /**
      * Constructor.
@@ -97,11 +102,16 @@ public class OdbcRequestHandler implements SqlListenerRequestHandler {
      * @param ctx Context.
      * @param busyLock Shutdown latch.
      * @param maxCursors Maximum allowed cursors.
+     * @param distributedJoins Distributed joins flag.
+     * @param enforceJoinOrder Enforce join order flag.
      */
-    public OdbcRequestHandler(GridKernalContext ctx, GridSpinBusyLock busyLock, int maxCursors) {
+    public OdbcRequestHandler(GridKernalContext ctx, GridSpinBusyLock busyLock, int maxCursors,
+        boolean distributedJoins, boolean enforceJoinOrder) {
         this.ctx = ctx;
         this.busyLock = busyLock;
         this.maxCursors = maxCursors;
+        this.distributedJoins = distributedJoins;
+        this.enforceJoinOrder = enforceJoinOrder;
 
         log = ctx.log(getClass());
     }
@@ -116,9 +126,6 @@ public class OdbcRequestHandler implements SqlListenerRequestHandler {
 
         try {
             switch (req.command()) {
-                case HANDSHAKE:
-                    return performHandshake((SqlListenerHandshakeRequest)req);
-
                 case QRY_EXEC:
                     return executeQuery((SqlListenerQueryExecuteRequest)req);
 
@@ -146,40 +153,6 @@ public class OdbcRequestHandler implements SqlListenerRequestHandler {
     }
 
     /**
-     * {@link SqlListenerHandshakeRequest} command handler.
-     *
-     * @param req Handshake request.
-     * @return Response.
-     */
-    private SqlListenerResponse performHandshake(SqlListenerHandshakeRequest req) {
-        try {
-            SqlListenerProtocolVersion version = req.version();
-
-            if (version == SqlListenerProtocolVersion.UNKNOWN) {
-                IgniteProductVersion ver = ctx.grid().version();
-
-                String verStr = Byte.toString(ver.major()) + '.' + ver.minor() + '.' + ver.maintenance();
-
-                SqlListenerHandshakeResult res = new SqlListenerHandshakeResult(false, OdbcUtils.VER_LATEST.since(), verStr);
-
-                return new SqlListenerResponse(res);
-            }
-
-            SqlListenerHandshakeResult res = new SqlListenerHandshakeResult(true, null, null);
-
-            distributedJoins = req.distributedJoins();
-            enforceJoinOrder = req.enforceJoinOrder();
-
-            return new SqlListenerResponse(res);
-        }
-        catch (Exception e) {
-            U.error(log, "Failed to perform handshake [reqId=" + req.requestId() + ", req=" + req + ']', e);
-
-            return new SqlListenerResponse(SqlListenerResponse.STATUS_FAILED, e.toString());
-        }
-    }
-
-    /**
      * {@link SqlListenerQueryExecuteRequest} command handler.
      *
      * @param req Execute query request.

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
index 7e9c738..c332aad 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -157,6 +157,7 @@
     <ClCompile Include="..\..\..\odbc\src\config\configuration.cpp" />
     <ClCompile Include="..\..\..\odbc\src\config\connection_info.cpp" />
     <ClCompile Include="..\..\..\odbc\src\cursor.cpp" />
+    <ClCompile Include="..\..\..\odbc\src\log.cpp" />
     <ClCompile Include="..\..\..\odbc\src\protocol_version.cpp" />
     <ClCompile Include="..\..\..\odbc\src\result_page.cpp" />
     <ClCompile Include="..\..\..\odbc\src\row.cpp" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
index 6efc4b4..a344df9 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj.filters
@@ -118,6 +118,9 @@
     <ClCompile Include="..\..\src\api_robustness_test.cpp">
       <Filter>Code</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\odbc\src\log.cpp">
+      <Filter>Externals</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\test_type.h">
@@ -152,5 +155,6 @@
     <None Include="..\..\config\queries-default.xml">
       <Filter>Configs</Filter>
     </None>
+    <None Include="..\..\config\queries-test-default.xml" />
   </ItemGroup>
 </Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
index d182f93..ecf3c4b 100644
--- a/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/configuration_test.cpp
@@ -62,6 +62,15 @@ void CheckValidProtocolVersion(const char* connectStr, ignite::odbc::ProtocolVer
     BOOST_CHECK(cfg.GetProtocolVersion() == version);
 }
 
+void CheckSupportedProtocolVersion(const char* connectStr)
+{
+    Configuration cfg;
+
+    BOOST_CHECK_NO_THROW(cfg.FillFromConnectString(connectStr));
+
+    BOOST_CHECK(cfg.GetProtocolVersion().IsSupported());
+}
+
 void CheckInvalidProtocolVersion(const char* connectStr)
 {
     Configuration cfg;
@@ -71,6 +80,15 @@ void CheckInvalidProtocolVersion(const char* connectStr)
     BOOST_CHECK_THROW(cfg.GetProtocolVersion(), ignite::IgniteError);
 }
 
+void CheckUnsupportedProtocolVersion(const char* connectStr)
+{
+    Configuration cfg;
+
+    cfg.FillFromConnectString(connectStr);
+
+    BOOST_CHECK(!cfg.GetProtocolVersion().IsSupported());
+}
+
 void CheckValidBoolValue(const std::string& connectStr, const std::string& key, bool val)
 {
     Configuration cfg;
@@ -269,14 +287,27 @@ BOOST_AUTO_TEST_CASE(TestConnectStringInvalidVersion)
     CheckInvalidProtocolVersion("Protocol_Version=0;");
     CheckInvalidProtocolVersion("Protocol_Version=1;");
     CheckInvalidProtocolVersion("Protocol_Version=2;");
-    CheckInvalidProtocolVersion("Protocol_Version=1.6.1;");
-    CheckInvalidProtocolVersion("Protocol_Version=1.7.0;");
-    CheckInvalidProtocolVersion("Protocol_Version=1.8.1;");
+    CheckInvalidProtocolVersion("Protocol_Version=2.1;");
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringUnsupportedVersion)
+{
+    CheckUnsupportedProtocolVersion("Protocol_Version=1.6.1;");
+    CheckUnsupportedProtocolVersion("Protocol_Version=1.7.0;");
+    CheckUnsupportedProtocolVersion("Protocol_Version=1.8.1;");
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringValidVersion)
 {
-    CheckValidProtocolVersion("Protocol_Version=2.0.0;", ignite::odbc::ProtocolVersion::VERSION_2_0_0);
+    CheckValidProtocolVersion("Protocol_Version=2.1.0;", ignite::odbc::ProtocolVersion::VERSION_2_1_0);
+    CheckValidProtocolVersion("Protocol_Version=1.6.1;", ignite::odbc::ProtocolVersion(1, 6, 1));
+    CheckValidProtocolVersion("Protocol_Version=1.7.0;", ignite::odbc::ProtocolVersion(1, 7, 0));
+    CheckValidProtocolVersion("Protocol_Version=1.8.1;", ignite::odbc::ProtocolVersion(1, 8, 1));
+}
+
+BOOST_AUTO_TEST_CASE(TestConnectStringSupportedVersion)
+{
+    CheckSupportedProtocolVersion("Protocol_Version=2.1.0;");
 }
 
 BOOST_AUTO_TEST_CASE(TestConnectStringInvalidBoolKeys)

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc-test/src/queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/queries_test.cpp b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
index 0f9eaee..4f7a6e2 100644
--- a/modules/platforms/cpp/odbc-test/src/queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/queries_test.cpp
@@ -378,9 +378,9 @@ BOOST_AUTO_TEST_CASE(TestLegacyConnection)
     Connect("DRIVER={Apache Ignite};SERVER=127.0.0.1;PORT=11110;CACHE=cache");
 }
 
-BOOST_AUTO_TEST_CASE(TestConnectionProtocolVERSION_2_0_0)
+BOOST_AUTO_TEST_CASE(TestConnectionProtocolVersion_2_1_0)
 {
-    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache;PROTOCOL_VERSION=2.0.0");
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;CACHE=cache;PROTOCOL_VERSION=2.1.0");
 }
 
 BOOST_AUTO_TEST_CASE(TestTwoRowsInt8)

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/message.h b/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
index 60b2d9b..aca214a 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/message.h
@@ -77,7 +77,7 @@ namespace ignite
              * @param distributedJoins Distributed joins flag.
              * @param enforceJoinOrder Enforce join order flag.
              */
-            HandshakeRequest(int64_t version, bool distributedJoins, bool enforceJoinOrder) :
+            HandshakeRequest(const ProtocolVersion& version, bool distributedJoins, bool enforceJoinOrder) :
                 version(version),
                 distributedJoins(distributedJoins),
                 enforceJoinOrder(enforceJoinOrder)
@@ -101,7 +101,9 @@ namespace ignite
             {
                 writer.WriteInt8(RequestType::HANDSHAKE);
 
-                writer.WriteInt64(version);
+                writer.WriteInt16(version.GetMajor());
+                writer.WriteInt16(version.GetMinor());
+                writer.WriteInt16(version.GetMaintenance());
 
                 writer.WriteBool(distributedJoins);
                 writer.WriteBool(enforceJoinOrder);
@@ -109,7 +111,7 @@ namespace ignite
 
         private:
             /** Protocol version. */
-            int64_t version;
+            ProtocolVersion version;
 
             /** Distributed joins flag. */
             bool distributedJoins;
@@ -508,7 +510,7 @@ namespace ignite
         /**
          * Handshake response.
          */
-        class HandshakeResponse : public Response
+        class HandshakeResponse
         {
         public:
             /**
@@ -516,8 +518,8 @@ namespace ignite
              */
             HandshakeResponse() :
                 accepted(false),
-                protoVerSince(),
-                currentVer()
+                currentVer(),
+                error()
             {
                 // No-op.
             }
@@ -540,47 +542,52 @@ namespace ignite
             }
 
             /**
-             * Get host Apache Ignite version when protocol version has been introduced.
-             * @return Host Apache Ignite version when protocol version has been introduced.
+             * Get optional error.
+             * @return Optional error message.
              */
-            const std::string& ProtoVerSince() const
+            const std::string& GetError() const
             {
-                return protoVerSince;
+                return error;
             }
 
             /**
              * Current host Apache Ignite version.
              * @return Current host Apache Ignite version.
              */
-            const std::string& CurrentVer() const
+            const ProtocolVersion& GetCurrentVer() const
             {
                 return currentVer;
             }
 
-        private:
             /**
              * Read response using provided reader.
              * @param reader Reader.
              */
-            virtual void ReadOnSuccess(ignite::impl::binary::BinaryReaderImpl& reader)
+            void Read(ignite::impl::binary::BinaryReaderImpl& reader)
             {
                 accepted = reader.ReadBool();
 
                 if (!accepted)
                 {
-                    utility::ReadString(reader, protoVerSince);
-                    utility::ReadString(reader, currentVer);
+                    int16_t major = reader.ReadInt16();
+                    int16_t minor = reader.ReadInt16();
+                    int16_t maintenance = reader.ReadInt16();
+
+                    currentVer = ProtocolVersion(major, minor, maintenance);
+
+                    utility::ReadString(reader, error);
                 }
             }
 
+        private:
             /** Handshake accepted. */
             bool accepted;
 
-            /** Host Apache Ignite version when protocol version has been introduced. */
-            std::string protoVerSince;
+            /** Node's protocol version. */
+            ProtocolVersion currentVer;
 
-            /** Current host Apache Ignite version. */
-            std::string currentVer;
+            /** Optional error message. */
+            std::string error;
         };
 
         /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h b/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
index bb42dd4..a3cb88e 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/protocol_version.h
@@ -21,7 +21,7 @@
 #include <stdint.h>
 
 #include <string>
-#include <map>
+#include <set>
 
 namespace ignite
 {
@@ -31,24 +31,17 @@ namespace ignite
         class ProtocolVersion
         {
         public:
-            /** String to version map type alias. */
-            typedef std::map<std::string, ProtocolVersion> StringToVersionMap;
+            /** Current protocol version. */
+            static const ProtocolVersion VERSION_2_1_0;
 
-            /** Version to string map type alias. */
-            typedef std::map<ProtocolVersion, std::string> VersionToStringMap;
-
-            /** First version of the protocol that was introduced in Ignite 2.0.0. */
-            static const ProtocolVersion VERSION_2_0_0;
-
-            /** Unknown version of the protocol. */
-            static const ProtocolVersion VERSION_UNKNOWN;
+            typedef std::set<ProtocolVersion> VersionSet;
 
             /**
              * Get string to version map.
              *
              * @return String to version map.
              */
-            static const StringToVersionMap& GetMap();
+            static const VersionSet& GetSupported();
 
             /**
              * Get current version.
@@ -69,25 +62,59 @@ namespace ignite
             /**
              * Convert to string value.
              *
-             * @throw IgniteException if version is unknow parsed.
-             * @param version Version string to parse.
              * @return Protocol version.
              */
-            const std::string& ToString() const;
+            std::string ToString() const;
 
             /**
-             * Get int value.
+             * Default constructor.
+             */
+            ProtocolVersion();
+
+            /**
+             * Constructor.
              *
-             * @return Integer value.
+             * @param vmajor Major version part.
+             * @param vminor Minor version part.
+             * @param vmaintenance Maintenance version part.
              */
-            int64_t GetIntValue() const;
+            ProtocolVersion(int16_t vmajor, int16_t vminor, int16_t vmaintenance);
 
             /**
-             * Check if the version is unknown.
+             * Get major part.
              *
-             * @return True if the version is unknown.
+             * @return Major part.
              */
-            bool IsUnknown() const;
+            int16_t GetMajor() const;
+
+            /**
+             * Get minor part.
+             *
+             * @return Minor part.
+             */
+            int16_t GetMinor() const;
+
+            /**
+             * Get maintenance part.
+             *
+             * @return Maintenance part.
+             */
+            int16_t GetMaintenance() const;
+
+            /**
+             * Check if the version is supported.
+             *
+             * @return True if the version is supported.
+             */
+            bool IsSupported() const;
+
+            /**
+             * Compare to another value.
+             *
+             * @param other Instance to compare to.
+             * @return Zero if equeals, negative number if less and positive if more.
+             */
+            int32_t Compare(const ProtocolVersion& other) const;
 
             /**
              * Comparison operator.
@@ -144,33 +171,17 @@ namespace ignite
             friend bool operator>=(const ProtocolVersion& val1, const ProtocolVersion& val2);
 
         private:
-            /**
-             * Constructor.
-             *
-             * @param val Underlying value.
-             */
-            explicit ProtocolVersion(int64_t val);
-            
-            /**
-             * Make int value for the version.
-             *
-             * @param major Major version.
-             * @param minor Minor version.
-             * @param revision Revision.
-             * @return Int value for the version.
-             */
-            static int64_t MakeVersion(uint16_t major, uint16_t minor, uint16_t revision);
-
-            ProtocolVersion();
+            /** Set of supported versions. */
+            const static VersionSet supported;
 
-            /** String to version map. */
-            static const StringToVersionMap stringToVersionMap;
+            /** Major part. */
+            int16_t vmajor;
 
-            /** Version to string map. */
-            static const VersionToStringMap versionToStringMap;
+            /** Minor part. */
+            int16_t vminor;
 
-            /** Underlying int value. */
-            int64_t val;
+            /** Maintenance part. */
+            int16_t vmaintenance;
         };
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp b/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
index 4a88052..36cb5e8 100644
--- a/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
+++ b/modules/platforms/cpp/odbc/os/win/src/system/ui/dsn_configuration_window.cpp
@@ -138,14 +138,14 @@ namespace ignite
 
                     int id = 0;
 
-                    const ProtocolVersion::StringToVersionMap& versionMap = ProtocolVersion::GetMap();
+                    const ProtocolVersion::VersionSet& supported = ProtocolVersion::GetSupported();
 
-                    ProtocolVersion::StringToVersionMap::const_iterator it;
-                    for (it = versionMap.begin(); it != versionMap.end(); ++it)
+                    ProtocolVersion::VersionSet::const_iterator it;
+                    for (it = supported.begin(); it != supported.end(); ++it)
                     {
-                        protocolVersionComboBox->AddString(it->first);
+                        protocolVersionComboBox->AddString(it->ToString());
 
-                        if (it->second == config.GetProtocolVersion())
+                        if (*it == config.GetProtocolVersion())
                             protocolVersionComboBox->SetSelection(id);
 
                         ++id;

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc/src/connection.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/connection.cpp b/modules/platforms/cpp/odbc/src/connection.cpp
index 62194d0..b9c15e5 100644
--- a/modules/platforms/cpp/odbc/src/connection.cpp
+++ b/modules/platforms/cpp/odbc/src/connection.cpp
@@ -255,6 +255,8 @@ namespace ignite
 
                 IGNITE_ERROR_1(IgniteError::IGNITE_ERR_GENERIC, "Can not receive message body");
             }
+
+            LOG_MSG("Message received: " << utility::HexDump(&msg[0], msg.size()));
         }
 
         size_t Connection::ReceiveAll(void* dst, size_t len)
@@ -321,13 +323,13 @@ namespace ignite
         {
             bool distributedJoins = false;
             bool enforceJoinOrder = false;
-            int64_t protocolVersion = 0;
+            ProtocolVersion protocolVersion;
 
             try
             {
                 distributedJoins = config.IsDistributedJoins();
                 enforceJoinOrder = config.IsEnforceJoinOrder();
-                protocolVersion = config.GetProtocolVersion().GetIntValue();
+                protocolVersion = config.GetProtocolVersion();
             }
             catch (const IgniteError& err)
             {
@@ -336,6 +338,13 @@ namespace ignite
                 return SqlResult::AI_ERROR;
             }
 
+            if (!protocolVersion.IsSupported())
+            {
+                AddStatusRecord(SqlState::S01S00_INVALID_CONNECTION_STRING_ATTRIBUTE, "Protocol version is not supported: " + protocolVersion.ToString());
+
+                return SqlResult::AI_ERROR;
+            }
+
             HandshakeRequest req(protocolVersion, distributedJoins, enforceJoinOrder);
             HandshakeResponse rsp;
 
@@ -350,27 +359,19 @@ namespace ignite
                 return SqlResult::AI_ERROR;
             }
 
-            if (rsp.GetStatus() != ResponseStatus::SUCCESS)
-            {
-                LOG_MSG("Error: " << rsp.GetError().c_str());
-
-                AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, rsp.GetError());
-
-                InternalRelease();
-
-                return SqlResult::AI_ERROR;
-            }
-
             if (!rsp.IsAccepted())
             {
                 LOG_MSG("Hanshake message has been rejected.");
 
                 std::stringstream constructor;
 
-                constructor << "Node rejected handshake message. "
-                    << "Current node Apache Ignite version: " << rsp.CurrentVer() << ", "
-                    << "node protocol version introduced in version: " << rsp.ProtoVerSince() << ", "
-                    << "driver protocol version introduced in version: " << config.GetProtocolVersion().ToString() << ".";
+                constructor << "Node rejected handshake message. ";
+
+                if (!rsp.GetError().empty())
+                    constructor << "Additional info: " << rsp.GetError();
+
+                constructor << "Current node Apache Ignite version: " << rsp.GetCurrentVer().ToString() << ", "
+                            << "driver protocol version introduced in version: " << config.GetProtocolVersion().ToString() << ".";
 
                 AddStatusRecord(SqlState::S08001_CANNOT_CONNECT, constructor.str());
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/dddc6d4a/modules/platforms/cpp/odbc/src/protocol_version.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/protocol_version.cpp b/modules/platforms/cpp/odbc/src/protocol_version.cpp
index 859135d..aa8915d 100644
--- a/modules/platforms/cpp/odbc/src/protocol_version.cpp
+++ b/modules/platforms/cpp/odbc/src/protocol_version.cpp
@@ -14,8 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <ignite/common/concurrent.h>
-#include <ignite/common/utils.h>
+
+#include <sstream>
+
 #include <ignite/ignite_error.h>
 
 #include "ignite/odbc/protocol_version.h"
@@ -25,112 +26,147 @@ namespace ignite
 {
     namespace odbc
     {
-        const ProtocolVersion ProtocolVersion::VERSION_2_0_0(MakeVersion(2,0,0));
-        const ProtocolVersion ProtocolVersion::VERSION_UNKNOWN(INT64_MIN);
+        const ProtocolVersion ProtocolVersion::VERSION_2_1_0(ProtocolVersion(2,1,0));
 
-        ProtocolVersion::StringToVersionMap::value_type s2vInitVals[] = {
-            std::make_pair("2.0.0", ProtocolVersion::VERSION_2_0_0)
+        ProtocolVersion::VersionSet::value_type supportedArray[] = {
+            ProtocolVersion::VERSION_2_1_0
         };
 
-        const ProtocolVersion::StringToVersionMap ProtocolVersion::stringToVersionMap(s2vInitVals,
-            s2vInitVals + (sizeof(s2vInitVals) / sizeof(s2vInitVals[0])));
-
-        ProtocolVersion::VersionToStringMap::value_type v2sInitVals[] = {
-            std::make_pair(ProtocolVersion::VERSION_2_0_0, "2.0.0")
-        };
+        const ProtocolVersion::VersionSet ProtocolVersion::supported(supportedArray,
+            supportedArray + (sizeof(supportedArray) / sizeof(supportedArray[0])));
 
-        const ProtocolVersion::VersionToStringMap ProtocolVersion::versionToStringMap(v2sInitVals,
-            v2sInitVals + (sizeof(v2sInitVals) / sizeof(v2sInitVals[0])));
-
-        ProtocolVersion::ProtocolVersion(int64_t val) :
-            val(val)
+        ProtocolVersion::ProtocolVersion(int16_t vmajor, int16_t vminor, int16_t vmaintenance) :
+            vmajor(vmajor),
+            vminor(vminor),
+            vmaintenance(vmaintenance)
         {
             // No-op.
         }
 
-        int64_t ProtocolVersion::MakeVersion(uint16_t major, uint16_t minor, uint16_t revision)
+        ProtocolVersion::ProtocolVersion() :
+            vmajor(0),
+            vminor(0),
+            vmaintenance(0)
         {
-            const static int64_t MASK = 0x000000000000FFFFLL;
-            return ((major & MASK) << 48) | ((minor & MASK) << 32) | ((revision & MASK) << 16);
+            // No-op.
         }
 
-        const ProtocolVersion::StringToVersionMap& ProtocolVersion::GetMap()
+        const ProtocolVersion::VersionSet& ProtocolVersion::GetSupported()
         {
-            return stringToVersionMap;
+            return supported;
         }
 
         const ProtocolVersion& ProtocolVersion::GetCurrent()
         {
-            return VERSION_2_0_0;
+            return VERSION_2_1_0;
+        }
+
+        void ThrowParseError()
+        {
+            throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
+                "Invalid version format. Valid format is X.Y.Z, where X, Y and Z are major, "
+                "minor and maintenance version parts of Ignite since which protocol is introduced.");
         }
 
         ProtocolVersion ProtocolVersion::FromString(const std::string& version)
         {
-            StringToVersionMap::const_iterator it = stringToVersionMap.find(common::ToLower(version));
+            ProtocolVersion res;
+
+            std::stringstream buf(version);
+
+            buf >> res.vmajor;
+
+            if (!buf.good())
+                ThrowParseError();
+
+            if (buf.get() != '.' || !buf.good())
+                ThrowParseError();
+
+            buf >> res.vminor;
 
-            if (it == stringToVersionMap.end())
-            {
-                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
-                    "Invalid version format. Valid format is X.Y.Z, where X, Y and Z are major "
-                    "and minor versions and revision of Ignite since which protocol is introduced.");
-            }
+            if (!buf.good())
+                ThrowParseError();
 
-            return it->second;
+            if (buf.get() != '.' || !buf.good())
+                ThrowParseError();
+
+            buf >> res.vmaintenance;
+
+            if (buf.bad())
+                ThrowParseError();
+
+            return res;
         }
 
-        const std::string& ProtocolVersion::ToString() const
+        std::string ProtocolVersion::ToString() const
         {
-            VersionToStringMap::const_iterator it = versionToStringMap.find(*this);
+            std::stringstream buf;
+            buf << vmajor << '.' << vminor << '.' << vmaintenance;
 
-            if (it == versionToStringMap.end())
-            {
-                throw IgniteError(IgniteError::IGNITE_ERR_GENERIC,
-                    "Unknown protocol version can not be converted to string.");
-            }
+            return buf.str();
+        }
 
-            return it->second;
+        int16_t ProtocolVersion::GetMajor() const
+        {
+            return vmajor;
         }
 
-        int64_t ProtocolVersion::GetIntValue() const
+        int16_t ProtocolVersion::GetMinor() const
         {
-            assert(!IsUnknown());
+            return vminor;
+        }
 
-            return val;
+        int16_t ProtocolVersion::GetMaintenance() const
+        {
+            return vmaintenance;
         }
 
-        bool ProtocolVersion::IsUnknown() const
+        bool ProtocolVersion::IsSupported() const
         {
-            return *this == VERSION_UNKNOWN;
+            return supported.count(*this) != 0;
+        }
+
+        int32_t ProtocolVersion::Compare(const ProtocolVersion& other) const
+        {
+            int32_t res = vmajor - other.vmajor;
+
+            if (res == 0)
+                res = vminor - other.vminor;
+
+            if (res == 0)
+                res = vmaintenance - other.vmaintenance;
+
+            return res;
         }
 
         bool operator==(const ProtocolVersion& val1, const ProtocolVersion& val2)
         {
-            return val1.val == val2.val;
+            return val1.Compare(val2) == 0;
         }
 
         bool operator!=(const ProtocolVersion& val1, const ProtocolVersion& val2)
         {
-            return val1.val != val2.val;
+            return val1.Compare(val2) != 0;
         }
 
         bool operator<(const ProtocolVersion& val1, const ProtocolVersion& val2)
         {
-            return val1.val < val2.val;
+            return val1.Compare(val2) < 0;
         }
 
         bool operator<=(const ProtocolVersion& val1, const ProtocolVersion& val2)
         {
-            return val1.val <= val2.val;
+            return val1.Compare(val2) <= 0;
         }
 
         bool operator>(const ProtocolVersion& val1, const ProtocolVersion& val2)
         {
-            return val1.val > val2.val;
+            return val1.Compare(val2) > 0;
         }
 
         bool operator>=(const ProtocolVersion& val1, const ProtocolVersion& val2)
         {
-            return val1.val >= val2.val;
+            return val1.Compare(val2) >= 0;
         }
     }
 }


[10/13] ignite git commit: Optional optimization to all client caches on client join.

Posted by sb...@apache.org.
Optional optimization to all client caches on client join.


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

Branch: refs/heads/ignite-5009
Commit: 68b68381d0c3c3e394a843fb22eed010b6f0a421
Parents: 70db21c
Author: sboikov <sb...@gridgain.com>
Authored: Wed May 10 11:26:38 2017 +0300
Committer: sboikov <sb...@gridgain.com>
Committed: Wed May 10 11:26:38 2017 +0300

----------------------------------------------------------------------
 .../apache/ignite/IgniteSystemProperties.java   |   3 +
 .../cache/DynamicCacheChangeBatch.java          |  17 ++
 .../processors/cache/GridCacheProcessor.java    |  23 +-
 .../ignite/spi/discovery/tcp/ClientImpl.java    |  21 +-
 .../ignite/spi/discovery/tcp/ServerImpl.java    |   2 +
 .../spi/discovery/tcp/TcpDiscoverySpi.java      |   7 +
 .../cache/distributed/CacheStartOnJoinTest.java | 250 +++++++++++++++++++
 .../testframework/junits/GridAbstractTest.java  |  12 +
 .../testsuites/IgniteCacheTestSuite4.java       |   2 +
 9 files changed, 334 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index 96930f8..7e92cf3 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -586,6 +586,9 @@ public final class IgniteSystemProperties {
     /** Cache start size for on-heap maps. Defaults to 4096. */
     public static final String IGNITE_CACHE_START_SIZE = "IGNITE_CACHE_START_SIZE";
 
+    /** */
+    public static final String IGNITE_START_CACHES_ON_JOIN = "IGNITE_START_CACHES_ON_JOIN";
+
     /** Returns true for system properties only avoiding sending sensitive information. */
     private static final IgnitePredicate<Map.Entry<String, String>> PROPS_FILTER = new IgnitePredicate<Map.Entry<String, String>>() {
         @Override public boolean apply(final Map.Entry<String, String> entry) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java
index a250063..66e780f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeBatch.java
@@ -47,6 +47,9 @@ public class DynamicCacheChangeBatch implements DiscoveryCustomMessage {
     /** */
     private boolean clientReconnect;
 
+    /** */
+    private boolean startCaches;
+
     /**
      * @param reqs Requests.
      */
@@ -114,6 +117,20 @@ public class DynamicCacheChangeBatch implements DiscoveryCustomMessage {
     }
 
     /**
+     * @return {@code True} if required to start all caches on client node.
+     */
+    public boolean startCaches() {
+        return startCaches;
+    }
+
+    /**
+     * @param startCaches {@code True} if required to start all caches on client node.
+     */
+    public void startCaches(boolean startCaches) {
+        this.startCaches = startCaches;
+    }
+
+    /**
      * @return {@code True} if request should trigger partition exchange.
      */
     public boolean exchangeNeeded() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index d6225c0..87aaee0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -43,6 +43,7 @@ import javax.management.JMException;
 import javax.management.MBeanServer;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheExistsException;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CacheRebalanceMode;
@@ -164,6 +165,10 @@ import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isNearE
  */
 @SuppressWarnings({"unchecked", "TypeMayBeWeakened", "deprecation"})
 public class GridCacheProcessor extends GridProcessorAdapter {
+    /** */
+    private final boolean START_CLIENT_CACHES =
+        IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_START_CACHES_ON_JOIN, false);
+
     /** Shared cache context. */
     private GridCacheSharedContext<?, ?> sharedCtx;
 
@@ -873,7 +878,8 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
                 boolean loc = desc.locallyConfigured();
 
-                if (loc || (desc.receivedOnDiscovery() && CU.affinityNode(locNode, filter))) {
+                if (loc || (desc.receivedOnDiscovery() &&
+                    (startAllCachesOnClientStart() || CU.affinityNode(locNode, filter)))) {
                     boolean started = desc.onStart();
 
                     assert started : "Failed to change started flag for locally configured cache: " + desc;
@@ -2166,6 +2172,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
         batch.clientReconnect(reconnect);
 
+        if (ctx.localNodeId().equals(joiningNodeId))
+            batch.startCaches(startAllCachesOnClientStart());
+
         // Reset random batch ID so that serialized batches with the same descriptors will be exactly the same.
         batch.id(null);
 
@@ -2244,6 +2253,13 @@ public class GridCacheProcessor extends GridProcessorAdapter {
         }
     }
 
+    /**
+     * @return {@code True} if need locally start all existing caches on client node start.
+     */
+    private boolean startAllCachesOnClientStart() {
+        return START_CLIENT_CACHES && ctx.clientNode();
+    }
+
     /** {@inheritDoc} */
     @Override public void onJoiningNodeDataReceived(JoiningNodeDiscoveryData data) {
         if (data.hasJoiningNodeData()) {
@@ -2382,6 +2398,11 @@ public class GridCacheProcessor extends GridProcessorAdapter {
                         ctx.discovery().addClientNode(cacheName, tup.getKey(), tup.getValue());
                 }
             }
+
+            if (batch.startCaches()) {
+                for (Map.Entry<String, DynamicCacheDescriptor> entry : registeredCaches.entrySet())
+                    ctx.discovery().addClientNode(entry.getKey(), joiningNodeId, false);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
index b5b4c77..4c7199c 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
@@ -136,6 +136,9 @@ class ClientImpl extends TcpDiscoveryImpl {
     /** Remote nodes. */
     private final ConcurrentMap<UUID, TcpDiscoveryNode> rmtNodes = new ConcurrentHashMap8<>();
 
+    /** */
+    private final List<DiscoveryDataPacket> delayDiscoData = new ArrayList<>();
+
     /** Topology history. */
     private final NavigableMap<Long, Collection<ClusterNode>> topHist = new TreeMap<>();
 
@@ -1751,6 +1754,8 @@ class ClientImpl extends TcpDiscoveryImpl {
 
             nodeAdded = false;
 
+            delayDiscoData.clear();
+
             IgniteClientDisconnectedCheckedException err =
                 new IgniteClientDisconnectedCheckedException(null, "Failed to ping node, " +
                     "client node disconnected.");
@@ -1774,6 +1779,7 @@ class ClientImpl extends TcpDiscoveryImpl {
             joinCnt++;
 
             T2<SocketStream, Boolean> joinRes;
+
             try {
                 joinRes = joinTopology(false, spi.joinTimeout);
             }
@@ -1919,8 +1925,12 @@ class ClientImpl extends TcpDiscoveryImpl {
 
                         DiscoveryDataPacket dataPacket = msg.gridDiscoveryData();
 
-                        if (dataPacket != null && dataPacket.hasJoiningNodeData())
-                            spi.onExchange(dataPacket, U.resolveClassLoader(spi.ignite().configuration()));
+                        if (dataPacket != null && dataPacket.hasJoiningNodeData()) {
+                            if (joining())
+                                delayDiscoData.add(dataPacket);
+                            else
+                                spi.onExchange(dataPacket, U.resolveClassLoader(spi.ignite().configuration()));
+                        }
                     }
                 }
                 else {
@@ -1944,6 +1954,13 @@ class ClientImpl extends TcpDiscoveryImpl {
                     if (dataContainer != null)
                         spi.onExchange(dataContainer, U.resolveClassLoader(spi.ignite().configuration()));
 
+                    if (!delayDiscoData.isEmpty()) {
+                        for (DiscoveryDataPacket data : delayDiscoData)
+                            spi.onExchange(data, U.resolveClassLoader(spi.ignite().configuration()));
+
+                        delayDiscoData.clear();
+                    }
+
                     locNode.setAttributes(msg.clientNodeAttributes());
                     locNode.visible(true);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
index 6a10ec2..663040d 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
@@ -2505,6 +2505,8 @@ class ServerImpl extends TcpDiscoveryImpl {
          * @param msg Message to process.
          */
         @Override protected void processMessage(TcpDiscoveryAbstractMessage msg) {
+            spi.startMessageProcess(msg);
+
             sendMetricsUpdateMessage();
 
             DebugLogger log = messageLogger(msg);

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
index 99a7dac..46ede4d 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
@@ -1465,6 +1465,13 @@ public class TcpDiscoverySpi extends IgniteSpiAdapter implements DiscoverySpi {
     }
 
     /**
+     * @param msg Message.
+     */
+    protected void startMessageProcess(TcpDiscoveryAbstractMessage msg) {
+        // No-op, intended for usage in tests.
+    }
+
+    /**
      * Writes message to the socket.
      *
      * @param sock Socket.

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java
new file mode 100644
index 0000000..321faf8
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheStartOnJoinTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.distributed;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CyclicBarrier;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.MemoryConfiguration;
+import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryJoinRequestMessage;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+
+/**
+ *
+ */
+@SuppressWarnings("unchecked")
+public class CacheStartOnJoinTest extends GridCommonAbstractTest {
+    /** */
+    private static TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** Iteration. */
+    private static final int ITERATIONS = 3;
+
+    /** */
+    private boolean client;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        TcpDiscoverySpi testSpi = new TcpDiscoverySpi() {
+            /** */
+            private boolean delay = true;
+
+            @Override protected void writeToSocket(Socket sock, OutputStream out, TcpDiscoveryAbstractMessage msg, long timeout) throws IOException, IgniteCheckedException {
+                super.writeToSocket(sock, out, msg, timeout);
+            }
+
+            @Override protected void startMessageProcess(TcpDiscoveryAbstractMessage msg) {
+                if (getTestIgniteInstanceName(0).equals(ignite.name())) {
+                    if (msg instanceof TcpDiscoveryJoinRequestMessage) {
+                        TcpDiscoveryJoinRequestMessage msg0 = (TcpDiscoveryJoinRequestMessage)msg;
+
+                        if (msg0.client() && delay) {
+                            log.info("Delay join processing: " + msg0);
+
+                            delay = false;
+
+                            doSleep(5000);
+                        }
+                    }
+                }
+
+                super.startMessageProcess(msg);
+            }
+        };
+
+        testSpi.setIpFinder(ipFinder);
+        testSpi.setJoinTimeout(60_000);
+
+        cfg.setDiscoverySpi(testSpi);
+
+        MemoryConfiguration memCfg = new MemoryConfiguration();
+        memCfg.setPageSize(1024);
+        memCfg.setDefaultMemoryPolicySize(50 * 1024 * 1024);
+
+        cfg.setMemoryConfiguration(memCfg);
+
+        cfg.setClientMode(client);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected long getTestTimeout() {
+        return 10 * 60 * 1000L;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        System.setProperty(IgniteSystemProperties.IGNITE_START_CACHES_ON_JOIN, "true");
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        System.clearProperty(IgniteSystemProperties.IGNITE_START_CACHES_ON_JOIN);
+
+        super.afterTestsStopped();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testConcurrentClientsStart1() throws Exception {
+        concurrentClientsStart(false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testConcurrentClientsStart2() throws Exception {
+        concurrentClientsStart(true);
+    }
+
+    /**
+     * @param createCache If {@code true} concurrently calls getOrCreateCaches.
+     * @throws Exception If failed.
+     */
+    private void concurrentClientsStart(boolean createCache) throws Exception {
+        for (int i = 0; i < ITERATIONS; i++) {
+            try {
+                log.info("Iteration: " + (i + 1) + '/' + ITERATIONS);
+
+                doTest(createCache);
+            }
+            finally {
+                stopAllGrids(true);
+            }
+        }
+    }
+
+    /**
+     * @param createCache If {@code true} concurrently calls getOrCreateCaches.
+     * @throws Exception If failed.
+     */
+    private void doTest(final boolean createCache) throws Exception {
+        client = false;
+
+        final int CLIENTS = 5;
+        final int SRVS = 4;
+
+        Ignite srv = startGrids(SRVS);
+
+        srv.getOrCreateCaches(cacheConfigurations());
+
+        final CyclicBarrier b = new CyclicBarrier(CLIENTS);
+
+        client = true;
+
+        GridTestUtils.runMultiThreaded(new IgniteInClosure<Integer>() {
+            @Override public void apply(Integer idx) {
+                try {
+                    b.await();
+
+                    Ignite node = startGrid(idx + SRVS);
+
+                    if (createCache) {
+                        for (int c = 0; c < 5; c++) {
+                            for (IgniteCache cache : node.getOrCreateCaches(cacheConfigurations())) {
+                                cache.put(c, c);
+
+                                assertEquals(c, cache.get(c));
+                            }
+                        }
+                    }
+                }
+                catch (Exception e) {
+                    throw new IgniteException(e);
+                }
+            }
+        }, CLIENTS, "start-client");
+
+        final int NODES = CLIENTS + SRVS;
+
+        for (int i = 0; i < CLIENTS + 1; i++) {
+            Ignite node = ignite(i);
+
+            log.info("Check node: " + node.name());
+
+            assertEquals((Boolean)(i >= SRVS), node.configuration().isClientMode());
+
+            for (int c = 0; c < 5; c++) {
+                Collection<ClusterNode> nodes = node.cluster().forCacheNodes("cache-" + c).nodes();
+
+                assertEquals(NODES, nodes.size());
+            }
+
+            for (int c = 0; c < 5; c++) {
+                for (IgniteCache cache : node.getOrCreateCaches(cacheConfigurations())) {
+                    cache.put(c, c);
+
+                    assertEquals(c, cache.get(c));
+                }
+            }
+        }
+    }
+
+    /**
+     * @return Cache configurations.
+     */
+    private Collection<CacheConfiguration> cacheConfigurations() {
+        List<CacheConfiguration> ccfgs = new ArrayList<>();
+
+        for (int i = 0; i < 5; i++)
+            ccfgs.add(cacheConfiguration("cache-" + i));
+
+        return ccfgs;
+    }
+
+    /**
+     * @param cacheName Cache name.
+     * @return Cache configuration.
+     */
+    private CacheConfiguration cacheConfiguration(String cacheName) {
+        CacheConfiguration ccfg = new CacheConfiguration(cacheName);
+
+        ccfg.setName(cacheName);
+        ccfg.setAtomicityMode(TRANSACTIONAL);
+        ccfg.setAffinity(new RendezvousAffinityFunction(false, 16));
+
+        return ccfg;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index b6940d2..8603d77 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -2056,6 +2056,18 @@ public abstract class GridAbstractTest extends TestCase {
     }
 
     /**
+     * @param millis Time to sleep.
+     */
+    public static void doSleep(long millis) {
+        try {
+            U.sleep(millis);
+        }
+        catch (Exception e) {
+            throw new IgniteException();
+        }
+    }
+
+    /**
      *
      */
     private static interface WriteReplaceOwner {

http://git-wip-us.apache.org/repos/asf/ignite/blob/68b68381/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
index 8340cd7..1023140 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
@@ -85,6 +85,7 @@ import org.apache.ignite.internal.processors.cache.distributed.CacheAffinityEarl
 import org.apache.ignite.internal.processors.cache.distributed.CacheAtomicPrimarySyncBackPressureTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheGetFutureHangsSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheNoValueClassOnServerNodeTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheStartOnJoinTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheCreatePutMultiNodeSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteCacheCreatePutTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteCachePrimarySyncTest;
@@ -220,6 +221,7 @@ public class IgniteCacheTestSuite4 extends TestSuite {
         suite.addTestSuite(CacheAffinityEarlyTest.class);
         suite.addTestSuite(IgniteCacheCreatePutMultiNodeSelfTest.class);
         suite.addTestSuite(IgniteCacheCreatePutTest.class);
+        suite.addTestSuite(CacheStartOnJoinTest.class);
 
         suite.addTestSuite(GridCacheTxLoadFromStoreOnLockSelfTest.class);
 


[03/13] ignite git commit: IGNITE-5172 .NET: Fix type name parser and resolver to handle arrays and simple names

Posted by sb...@apache.org.
IGNITE-5172 .NET: Fix type name parser and resolver to handle arrays and simple names

This closes #1909


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

Branch: refs/heads/ignite-5009
Commit: ba21c46cc15661d550e9018349ad266517446131
Parents: dddc6d4
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Fri May 5 18:38:29 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Fri May 5 18:38:29 2017 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.Tests.csproj             |   1 +
 .../Binary/BinaryDynamicRegistrationTest.cs     |  40 +++++++
 .../Binary/BinaryNameMapperTest.cs              |   7 ++
 .../Binary/TypeNameParserTest.cs                |  93 ++++++++++++---
 .../Binary/TypeResolverTest.cs                  | 104 +++++++++++++++++
 .../Cache/Query/CacheQueriesTest.cs             |   5 +-
 .../Apache.Ignite.Core.Tests/DeploymentTest.cs  |   1 +
 .../Examples/ExamplesTest.cs                    |   5 +-
 .../Binary/BinaryBasicNameMapper.cs             |   6 +-
 .../Impl/Binary/BinaryProcessor.cs              |  15 +--
 .../Impl/Binary/BinaryReader.cs                 |   6 +-
 .../Impl/Binary/Marshaller.cs                   |  18 ++-
 .../Impl/Binary/TypeNameParser.cs               |  31 ++++-
 .../Impl/Binary/TypeResolver.cs                 | 115 +++++++++++++++----
 .../Impl/Memory/PlatformMemoryStream.cs         |   2 +-
 15 files changed, 380 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index c6b183b..7adbbbe 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -256,6 +256,7 @@
     <ProjectReference Include="..\Examples\Apache.Ignite.ExamplesDll\Apache.Ignite.ExamplesDll.csproj">
       <Project>{dfb08363-202e-412d-8812-349ef10a8702}</Project>
       <Name>Apache.Ignite.ExamplesDll</Name>
+      <Aliases>ExamplesDll</Aliases>
     </ProjectReference>
     <ProjectReference Include="..\Examples\Apache.Ignite.Examples\Apache.Ignite.Examples.csproj">
       <Project>{069fa680-3c4d-43a9-b84f-e67513b87827}</Project>

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
index 549e453..927aa32 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDynamicRegistrationTest.cs
@@ -18,6 +18,8 @@
 // ReSharper disable UnusedAutoPropertyAccessor.Local
 namespace Apache.Ignite.Core.Tests.Binary
 {
+    extern alias ExamplesDll;
+
     using System;
     using System.Collections;
     using System.Collections.Generic;
@@ -31,8 +33,11 @@ namespace Apache.Ignite.Core.Tests.Binary
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Tests.Compute;
+    using Apache.Ignite.ExamplesDll.Binary;
     using NUnit.Framework;
 
+    using ExamplesAccount = ExamplesDll::Apache.Ignite.ExamplesDll.Binary.Account;
+
     /// <summary>
     /// Tests the dynamic type registration.
     /// </summary>
@@ -329,6 +334,28 @@ namespace Apache.Ignite.Core.Tests.Binary
         }
 
         /// <summary>
+        /// Tests that types with same FullName from different assemblies are mapped to each other.
+        /// </summary>
+        [Test]
+        public void TestSameTypeInDifferentAssemblies()
+        {
+            using (var ignite1 = Ignition.Start(TestUtils.GetTestConfiguration()))
+            {
+                var cache1 = ignite1.CreateCache<int, ExamplesAccount>("acc");
+                cache1[1] = new ExamplesAccount(1, 2.2m);
+
+                using (var ignite2 = Ignition.Start(TestUtils.GetTestConfiguration(name: "ignite2")))
+                {
+                    var cache2 = ignite2.GetCache<int, Account>("acc");
+                    cache2[2] = new Account {Id = 2, Balance = 3.3m};
+
+                    Assert.AreEqual(1, cache2[1].Id);  // Read ExamplesAccount as Account.
+                    Assert.AreEqual(2, cache1[2].Id);  // Read Account as ExamplesAccount.
+                }
+            }
+        }
+
+        /// <summary>
         /// Tests the type registration.
         /// </summary>
         private static void Test(IIgnite ignite1, IIgnite ignite2)
@@ -492,3 +519,16 @@ namespace Apache.Ignite.Core.Tests.Binary
         }
     }
 }
+
+namespace Apache.Ignite.ExamplesDll.Binary
+{
+    /// <summary>
+    /// Copy of Account class in ExamplesDll. Same name and namespace, different assembly.
+    /// </summary>
+    public class Account
+    {
+        public int Id { get; set; }
+
+        public decimal Balance { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs
index b3ace97..ff1f91d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryNameMapperTest.cs
@@ -61,6 +61,13 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.BinaryNameMapperTest+Bar`1[[Apache.Ignite.Core.Tests." +
                             "Binary.BinaryNameMapperTest+Foo[]]][]", 
                             mapper.GetTypeName(typeof(Bar<Foo[]>[]).AssemblyQualifiedName));
+
+            // Open generics.
+            Assert.AreEqual("System.Collections.Generic.List`1",
+                mapper.GetTypeName(typeof(List<>).AssemblyQualifiedName));
+
+            Assert.AreEqual("System.Collections.Generic.Dictionary`2",
+                mapper.GetTypeName(typeof(Dictionary<,>).AssemblyQualifiedName));
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs
index f3394a3..e566a4b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeNameParserTest.cs
@@ -39,7 +39,7 @@ namespace Apache.Ignite.Core.Tests.Binary
         {
             // One letter.
             var res = TypeNameParser.Parse("x");
-            Assert.AreEqual("x", res.GetFullName());
+            Assert.AreEqual("x", res.GetNameWithNamespace());
             Assert.AreEqual("x", res.GetName());
             Assert.AreEqual(0, res.NameStart);
             Assert.AreEqual(0, res.NameEnd);
@@ -79,78 +79,115 @@ namespace Apache.Ignite.Core.Tests.Binary
         [Test]
         public void TestGenericTypes()
         {
-            // Custom strings.
+            // Simple name.
             var res = TypeNameParser.Parse("List`1[[Int]]");
             Assert.AreEqual("List`1", res.GetName());
-            Assert.AreEqual("List`1", res.GetFullName());
+            Assert.AreEqual("List`1", res.GetNameWithNamespace());
             Assert.AreEqual("Int", res.Generics.Single().GetName());
-            Assert.AreEqual("Int", res.Generics.Single().GetFullName());
+            Assert.AreEqual("Int", res.Generics.Single().GetNameWithNamespace());
+            
+            // Simple name array.
+            res = TypeNameParser.Parse("List`1[[Byte[]]]");
+            Assert.AreEqual("List`1", res.GetName());
+            Assert.AreEqual("List`1", res.GetNameWithNamespace());
+            Assert.AreEqual("Byte", res.Generics.Single().GetName());
+            Assert.AreEqual("Byte", res.Generics.Single().GetNameWithNamespace());
+            Assert.AreEqual("[]", res.Generics.Single().GetArray());
+
+            // Simple name two-dimension array.
+            res = TypeNameParser.Parse("List`1[[Byte[,]]]");
+            Assert.AreEqual("List`1", res.GetName());
+            Assert.AreEqual("List`1", res.GetNameWithNamespace());
+            Assert.AreEqual("Byte", res.Generics.Single().GetName());
+            Assert.AreEqual("Byte", res.Generics.Single().GetNameWithNamespace());
+            Assert.AreEqual("[,]", res.Generics.Single().GetArray());
+
+            // Simple name jagged array.
+            res = TypeNameParser.Parse("List`1[[Byte[][]]]");
+            Assert.AreEqual("List`1", res.GetName());
+            Assert.AreEqual("List`1", res.GetNameWithNamespace());
+            Assert.AreEqual("Byte", res.Generics.Single().GetName());
+            Assert.AreEqual("Byte", res.Generics.Single().GetNameWithNamespace());
+            Assert.AreEqual("[][]", res.Generics.Single().GetArray());
+
+            // Open generic.
+            res = TypeNameParser.Parse("List`1");
+            Assert.AreEqual("List`1", res.GetName());
+            Assert.AreEqual("List`1", res.GetNameWithNamespace());
+            Assert.IsEmpty(res.Generics);
 
             // One arg.
             res = TypeNameParser.Parse(typeof(List<int>).AssemblyQualifiedName);
             Assert.AreEqual("List`1", res.GetName());
-            Assert.AreEqual("System.Collections.Generic.List`1", res.GetFullName());
+            Assert.AreEqual("System.Collections.Generic.List`1", res.GetNameWithNamespace());
             Assert.IsTrue(res.GetAssemblyName().StartsWith("mscorlib,"));
 
             Assert.AreEqual(1, res.Generics.Count);
             var gen = res.Generics.Single();
             Assert.AreEqual("Int32", gen.GetName());
-            Assert.AreEqual("System.Int32", gen.GetFullName());
+            Assert.AreEqual("System.Int32", gen.GetNameWithNamespace());
             Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,"));
 
+            // One arg open.
+            res = TypeNameParser.Parse(typeof(List<>).AssemblyQualifiedName);
+            Assert.AreEqual("List`1", res.GetName());
+            Assert.AreEqual("System.Collections.Generic.List`1", res.GetNameWithNamespace());
+            Assert.IsTrue(res.GetAssemblyName().StartsWith("mscorlib,"));
+            Assert.IsEmpty(res.Generics);
+
             // Two args.
             res = TypeNameParser.Parse(typeof(Dictionary<int, string>).AssemblyQualifiedName);
             Assert.AreEqual("Dictionary`2", res.GetName());
-            Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetFullName());
+            Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetNameWithNamespace());
             Assert.IsTrue(res.GetAssemblyName().StartsWith("mscorlib,"));
 
             Assert.AreEqual(2, res.Generics.Count);
 
             gen = res.Generics.First();
             Assert.AreEqual("Int32", gen.GetName());
-            Assert.AreEqual("System.Int32", gen.GetFullName());
+            Assert.AreEqual("System.Int32", gen.GetNameWithNamespace());
             Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,"));
 
             gen = res.Generics.Last();
             Assert.AreEqual("String", gen.GetName());
-            Assert.AreEqual("System.String", gen.GetFullName());
+            Assert.AreEqual("System.String", gen.GetNameWithNamespace());
             Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,"));
 
             // Nested args.
             res = TypeNameParser.Parse(typeof(Dictionary<int, List<string>>).FullName);
 
             Assert.AreEqual("Dictionary`2", res.GetName());
-            Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetFullName());
+            Assert.AreEqual("System.Collections.Generic.Dictionary`2", res.GetNameWithNamespace());
             Assert.IsNull(res.GetAssemblyName());
 
             Assert.AreEqual(2, res.Generics.Count);
 
             gen = res.Generics.Last();
             Assert.AreEqual("List`1", gen.GetName());
-            Assert.AreEqual("System.Collections.Generic.List`1", gen.GetFullName());
+            Assert.AreEqual("System.Collections.Generic.List`1", gen.GetNameWithNamespace());
             Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,"));
             Assert.AreEqual(1, gen.Generics.Count);
 
             gen = gen.Generics.Single();
             Assert.AreEqual("String", gen.GetName());
-            Assert.AreEqual("System.String", gen.GetFullName());
+            Assert.AreEqual("System.String", gen.GetNameWithNamespace());
             Assert.IsTrue(gen.GetAssemblyName().StartsWith("mscorlib,"));
 
             // Nested class.
             res = TypeNameParser.Parse(typeof(NestedGeneric<int>).FullName);
 
             Assert.AreEqual("NestedGeneric`1", res.GetName());
-            Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.TypeNameParserTest+NestedGeneric`1", res.GetFullName());
+            Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.TypeNameParserTest+NestedGeneric`1", res.GetNameWithNamespace());
 
             gen = res.Generics.Single();
             Assert.AreEqual("Int32", gen.GetName());
-            Assert.AreEqual("System.Int32", gen.GetFullName());
+            Assert.AreEqual("System.Int32", gen.GetNameWithNamespace());
 
             res = TypeNameParser.Parse(typeof(NestedGeneric<int>.NestedGeneric2<string>).AssemblyQualifiedName);
             
             Assert.AreEqual("NestedGeneric2`1", res.GetName());
             Assert.AreEqual("Apache.Ignite.Core.Tests.Binary.TypeNameParserTest+NestedGeneric`1+NestedGeneric2`1", 
-                res.GetFullName());
+                res.GetNameWithNamespace());
 
             Assert.AreEqual(2, res.Generics.Count);
             Assert.AreEqual("Int32", res.Generics.First().GetName());
@@ -163,9 +200,30 @@ namespace Apache.Ignite.Core.Tests.Binary
         [Test]
         public void TestArrays()
         {
+            var res = TypeNameParser.Parse("Int32[]");
+            Assert.AreEqual("Int32", res.GetName());
+            Assert.AreEqual("Int32", res.GetNameWithNamespace());
+            Assert.AreEqual("Int32[]", res.GetFullName());
+            Assert.AreEqual("[]", res.GetArray());
+
+            res = TypeNameParser.Parse("Int32[*]");
+            Assert.AreEqual("Int32", res.GetName());
+            Assert.AreEqual("Int32", res.GetNameWithNamespace());
+            Assert.AreEqual("Int32[*]", res.GetFullName());
+            Assert.AreEqual("[*]", res.GetArray());
+
+            res = TypeNameParser.Parse("List`1[[Int32]][]");
+            Assert.AreEqual("List`1", res.GetName());
+            Assert.AreEqual("List`1", res.GetNameWithNamespace());
+            Assert.AreEqual("List`1[[Int32]][]", res.GetFullName());
+            Assert.AreEqual("[]", res.GetArray());
+
             CheckType(typeof(int[]));
+            CheckType(typeof(int).MakeArrayType(1));
             CheckType(typeof(int[,]));
+            CheckType(typeof(int[,,]));
             CheckType(typeof(int[][]));
+            CheckType(typeof(int[,,,][,,]));
             
             CheckType(typeof(List<int>[]));
             CheckType(typeof(List<int>[,]));
@@ -184,12 +242,9 @@ namespace Apache.Ignite.Core.Tests.Binary
             Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x["));
             Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x[[]"));
             Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`["));
-            Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`]"));
             Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`[ ]"));
             Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x,"));
-            Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`x"));
             Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`2[x"));
-            Assert.Throws<IgniteException>(() => TypeNameParser.Parse("x`2xx"));
         }
 
         /// <summary>
@@ -207,7 +262,7 @@ namespace Apache.Ignite.Core.Tests.Binary
 
             if (res.Generics == null)
             {
-                Assert.AreEqual(type.FullName, res.GetFullName() + res.GetArray());
+                Assert.AreEqual(type.FullName, res.GetNameWithNamespace() + res.GetArray());
             }
 
             Assert.AreEqual(type.FullName.Length + 2, res.AssemblyStart);

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs
index 7d37584..6ed1a5f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/TypeResolverTest.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Tests.Binary
     using System.Collections.Generic;
     using System.Linq;
     using System.Reflection;
+    using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Tests.TestDll;
     using NUnit.Framework;
@@ -31,6 +32,35 @@ namespace Apache.Ignite.Core.Tests.Binary
     public class TypeResolverTest
     {
         /// <summary>
+        /// Tests basic types.
+        /// </summary>
+        [Test]
+        public void TestBasicTypes()
+        {
+            var resolver = new TypeResolver();
+
+            Assert.AreEqual(typeof(int), resolver.ResolveType("System.Int32"));
+            Assert.AreEqual(GetType(), resolver.ResolveType(GetType().FullName));
+
+            Assert.IsNull(resolver.ResolveType("invalidType"));
+        }
+
+        /// <summary>
+        /// Tests basic types.
+        /// </summary>
+        [Test]
+        public void TestBasicTypesSimpleMapper()
+        {
+            var resolver = new TypeResolver();
+            var mapper = BinaryBasicNameMapper.SimpleNameInstance;
+
+            Assert.AreEqual(typeof(int), resolver.ResolveType("Int32", nameMapper: mapper));
+            Assert.AreEqual(GetType(), resolver.ResolveType("TypeResolverTest", nameMapper: mapper));
+
+            Assert.IsNull(resolver.ResolveType("invalidType", nameMapper: mapper));
+        }
+
+        /// <summary>
         /// Tests generic type resolve.
         /// </summary>
         [Test]
@@ -67,6 +97,80 @@ namespace Apache.Ignite.Core.Tests.Binary
         }
 
         /// <summary>
+        /// Tests generic type resolve.
+        /// </summary>
+        [Test]
+        public void TestGenericsSimpleName()
+        {
+            var resolver = new TypeResolver();
+            var mapper = BinaryBasicNameMapper.SimpleNameInstance;
+
+            Assert.AreEqual(typeof(TestGenericBinarizable<int>), 
+                resolver.ResolveType("TestGenericBinarizable`1[[Int32]]", nameMapper: mapper));
+
+            Assert.IsNull(resolver.ResolveType("TestGenericBinarizable`1[[Invalid-Type]]", nameMapper: mapper));
+
+            var testTypes = new[]
+            {
+                typeof (TestGenericBinarizable<int>),
+                typeof (TestGenericBinarizable<string>),
+                typeof (TestGenericBinarizable<TestGenericBinarizable<int>>),
+                typeof (TestGenericBinarizable<List<Tuple<int, string>>>),
+                typeof (TestGenericBinarizable<List<TestGenericBinarizable<List<Tuple<int, string>>>>>),
+                typeof (List<TestGenericBinarizable<List<TestGenericBinarizable<List<Tuple<int, string>>>>>>),
+                typeof (TestGenericBinarizable<int, string>),
+                typeof (TestGenericBinarizable<int, TestGenericBinarizable<string>>),
+                typeof (TestGenericBinarizable<int, string, Type>),
+                typeof (TestGenericBinarizable<int, string, TestGenericBinarizable<int, string, Type>>)
+            };
+
+            foreach (var type in testTypes)
+            {
+                var typeName = mapper.GetTypeName(type.AssemblyQualifiedName);
+                var resolvedType = resolver.ResolveType(typeName, nameMapper: mapper);
+                Assert.AreEqual(type, resolvedType);
+            }
+        }
+
+        /// <summary>
+        /// Tests array type resolve.
+        /// </summary>
+        [Test]
+        public void TestArrays()
+        {
+            var resolver = new TypeResolver();
+
+            Assert.AreEqual(typeof(int[]), resolver.ResolveType("System.Int32[]"));
+            Assert.AreEqual(typeof(int[][]), resolver.ResolveType("System.Int32[][]"));
+            Assert.AreEqual(typeof(int[,,][,]), resolver.ResolveType("System.Int32[,][,,]"));
+
+            Assert.AreEqual(typeof(int).MakeArrayType(1), resolver.ResolveType("System.Int32[*]"));
+            
+            Assert.AreEqual(typeof(TestGenericBinarizable<TypeResolverTest>[]), 
+                resolver.ResolveType("Apache.Ignite.Core.Tests.TestGenericBinarizable`1" +
+                                     "[[Apache.Ignite.Core.Tests.Binary.TypeResolverTest]][]"));
+        }
+
+        /// <summary>
+        /// Tests array type resolve.
+        /// </summary>
+        [Test]
+        public void TestArraysSimpleName()
+        {
+            var resolver = new TypeResolver();
+            var mapper = BinaryBasicNameMapper.SimpleNameInstance;
+
+            Assert.AreEqual(typeof(int[]), resolver.ResolveType("Int32[]", nameMapper: mapper));
+            Assert.AreEqual(typeof(int[][]), resolver.ResolveType("Int32[][]", nameMapper: mapper));
+            Assert.AreEqual(typeof(int[,,][,]), resolver.ResolveType("Int32[,][,,]", nameMapper: mapper));
+
+            Assert.AreEqual(typeof(int).MakeArrayType(1), resolver.ResolveType("Int32[*]", nameMapper: mapper));
+
+            Assert.AreEqual(typeof(TestGenericBinarizable<TypeResolverTest>[]),
+                resolver.ResolveType("TestGenericBinarizable`1[[TypeResolverTest]][]", nameMapper: mapper));
+        }
+
+        /// <summary>
         /// Tests loading a type from referenced assembly that is not yet loaded.
         /// </summary>
         [Test]

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
index 1fa993b..01277e1 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheQueriesTest.cs
@@ -30,7 +30,6 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Query;
     using Apache.Ignite.Core.Common;
-    using Apache.Ignite.Core.Impl.Binary;
     using NUnit.Framework;
 
     /// <summary>
@@ -442,7 +441,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         [Test]
         public void TestScanQueryBinary([Values(true, false)]  bool loc)
         {
-            CheckScanQuery<BinaryObject>(loc, true);
+            CheckScanQuery<IBinaryObject>(loc, true);
         }
 
         /// <summary>
@@ -460,7 +459,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         [Test]
         public void TestScanQueryPartitionsBinary([Values(true, false)]  bool loc)
         {
-            CheckScanQueryPartitions<BinaryObject>(loc, true);
+            CheckScanQueryPartitions<IBinaryObject>(loc, true);
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
index 74da531..cb97076 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/DeploymentTest.cs
@@ -79,6 +79,7 @@ namespace Apache.Ignite.Core.Tests
             {
                 "-springConfigUrl=" + springFile,
                 "-jvmClasspath=" + classpath,
+                "-assembly=" + Path.GetFileName(GetType().Assembly.Location),
                 "-J-ea",
                 "-J-Xms512m",
                 "-J-Xmx512m"

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
index e041fd7..9389185 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Examples/ExamplesTest.cs
@@ -17,12 +17,12 @@
 
 namespace Apache.Ignite.Core.Tests.Examples
 {
+    extern alias ExamplesDll;
     using System;
     using System.Collections.Generic;
     using System.IO;
     using System.Linq;
     using Apache.Ignite.Core.Tests.Process;
-    using Apache.Ignite.ExamplesDll.Compute;
     using NUnit.Framework;
 
     /// <summary>
@@ -130,7 +130,8 @@ namespace Apache.Ignite.Core.Tests.Examples
                 var args = new List<string>
                 {
                     "-configFileName=" + _configPath,
-                    "-assembly=" + typeof(AverageSalaryJob).Assembly.Location
+                    "-assembly=" + typeof(ExamplesDll::Apache.Ignite.ExamplesDll.Compute.AverageSalaryJob)
+                        .Assembly.Location
                 };
 
                 var proc = new IgniteProcess(args.ToArray());

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs
index 0a6406b..c75303f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryBasicNameMapper.cs
@@ -57,7 +57,7 @@ namespace Apache.Ignite.Core.Binary
             if (parsedName.Generics == null)
             {
                 // Generics are rare, use simpler logic for the common case.
-                var res = IsSimpleName ? parsedName.GetName() : parsedName.GetFullName();
+                var res = IsSimpleName ? parsedName.GetName() : parsedName.GetNameWithNamespace();
                 
                 var arr = parsedName.GetArray();
 
@@ -71,7 +71,7 @@ namespace Apache.Ignite.Core.Binary
 
             var nameFunc = IsSimpleName
                 ? (Func<TypeNameParser, string>) (x => x.GetName())
-                : (x => x.GetFullName());
+                : (x => x.GetNameWithNamespace());
 
             return BuildTypeName(parsedName, new StringBuilder(), nameFunc).ToString();
         }
@@ -94,7 +94,7 @@ namespace Apache.Ignite.Core.Binary
 
             var generics = typeName.Generics;
 
-            if (generics != null)
+            if (generics != null && generics.Count > 0)  // Generics are non-null but empty when unbound.
             {
                 sb.Append('[');
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
index 555a042..df30a6d 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryProcessor.cs
@@ -161,17 +161,17 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// Registers the type.
         /// </summary>
         /// <param name="id">The identifier.</param>
-        /// <param name="type">The type.</param>
+        /// <param name="typeName">The type name.</param>
         /// <returns>True if registration succeeded; otherwise, false.</returns>
-        public bool RegisterType(int id, Type type)
+        public bool RegisterType(int id, string typeName)
         {
-            Debug.Assert(type != null);
+            Debug.Assert(typeName != null);
             Debug.Assert(id != BinaryUtils.TypeUnregistered);
 
             return DoOutOp((int) Op.RegisterType, w =>
             {
                 w.WriteInt(id);
-                w.WriteString(type.AssemblyQualifiedName);
+                w.WriteString(typeName);
             }) == True;
         }
 
@@ -180,12 +180,9 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="id">The identifier.</param>
         /// <returns>Type or null.</returns>
-        public Type GetType(int id)
+        public string GetTypeName(int id)
         {
-            var typeName = DoOutInOp((int) Op.GetType, w => w.WriteInt(id),
-                r => Marshaller.StartUnmarshal(r).ReadString());
-
-            return new TypeResolver().ResolveType(typeName);
+            return DoOutInOp((int) Op.GetType, w => w.WriteInt(id), r => Marshaller.StartUnmarshal(r).ReadString());
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
index 49bab77..a5c6814 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
@@ -704,13 +704,13 @@ namespace Apache.Ignite.Core.Impl.Binary
                         {
                             throw new BinaryObjectException(string.Format(
                                 "Unknown type ID: {0}. " +
-                                "This usually indicates missing BinaryConfiguration." +
+                                "This usually indicates missing BinaryConfiguration. " +
                                 "Make sure that all nodes have the same BinaryConfiguration.", hdr.TypeId));
                         }
 
                         throw new BinaryObjectException(string.Format(
-                            "No matching type found for object [typeId={0}, typeName={1}]." +
-                            "This usually indicates that assembly with specified type is not loaded on a node." +
+                            "No matching type found for object [typeId={0}, typeName={1}]. " +
+                            "This usually indicates that assembly with specified type is not loaded on a node. " +
                             "When using Apache.Ignite.exe, make sure to load assemblies with -assembly parameter.",
                             desc.TypeId, desc.TypeName));
                     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
index 4707ce2..ea2964a 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -439,13 +439,21 @@ namespace Apache.Ignite.Core.Impl.Binary
             if (!userType)
                 return null;
 
-            if (requiresType)
+            if (requiresType && _ignite != null)
             {
                 // Check marshaller context for dynamically registered type.
-                var type = _ignite == null ? null : _ignite.BinaryProcessor.GetType(typeId);
+                var typeName = _ignite.BinaryProcessor.GetTypeName(typeId);
 
-                if (type != null)
-                    return AddUserType(type, typeId, GetTypeName(type), true, desc);
+                if (typeName != null)
+                {
+                    var type = new TypeResolver().ResolveType(typeName, nameMapper: 
+                        _cfg.NameMapper ?? GetDefaultNameMapper());
+
+                    if (type != null)
+                    {
+                        return AddUserType(type, typeId, GetTypeName(type), true, desc);
+                    }
+                }
             }
 
             var meta = GetBinaryType(typeId);
@@ -475,7 +483,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             var typeName = GetTypeName(type);
             var typeId = GetTypeId(typeName, _cfg.IdMapper);
 
-            var registered = _ignite != null && _ignite.BinaryProcessor.RegisterType(typeId, type);
+            var registered = _ignite != null && _ignite.BinaryProcessor.RegisterType(typeId, typeName);
 
             return AddUserType(type, typeId, typeName, registered, desc);
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs
index 527d47c..a925770 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs
@@ -78,6 +78,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         public int NameEnd { get; private set; }
 
         /// <summary>
+        /// Gets the name end.
+        /// </summary>
+        public int FullNameEnd { get; private set; }
+
+        /// <summary>
         /// Gets the start of the assembly name.
         /// </summary>
         public int AssemblyStart { get; private set; }
@@ -116,7 +121,7 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <summary>
         /// Gets the full type name (with namespace).
         /// </summary>
-        public string GetFullName()
+        public string GetNameWithNamespace()
         {
             if (NameEnd < 0)
                 return null;
@@ -125,6 +130,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         }
 
         /// <summary>
+        /// Gets the full name (with namespace, generics and arrays).
+        /// </summary>
+        public string GetFullName()
+        {
+            return _typeName.Substring(_start, FullNameEnd - _start + 1);
+        }
+
+        /// <summary>
         /// Gets the array part.
         /// </summary>
         public string GetArray()
@@ -164,6 +177,7 @@ namespace Apache.Ignite.Core.Impl.Binary
             ParseTypeName();
             ParseGeneric();
             ParseArrayDefinition();
+            FullNameEnd = End ? _pos : _pos - 1;
             ParseAssemblyName();
         }
 
@@ -183,7 +197,7 @@ namespace Apache.Ignite.Core.Impl.Binary
 
                 if (Char == '`')
                 {
-                    // Non-null ist indicates detected generic type.
+                    // Non-null list indicates detected generic type.
                     Generics = Generics ?? new List<TypeNameParser>();
                 }
 
@@ -207,6 +221,12 @@ namespace Apache.Ignite.Core.Impl.Binary
                 return;
             }
 
+            if (End || Char == ',')
+            {
+                // Open (unbound) generic.
+                return;
+            }
+
             if (Char != '[')
             {
                 throw new IgniteException("Invalid generic type name, number must be followed by '[': " + _typeName);
@@ -274,15 +294,18 @@ namespace Apache.Ignite.Core.Impl.Binary
                 {
                     if (!bracket)
                     {
-                        throw new IgniteException("Invalid array specification: " + _typeName);
+                        ArrayEnd = _pos - 1;
+                        return;
                     }
 
                     bracket = false;
                 }
-                else if (Char == ',')
+                else if (Char == ',' || Char == '*')
                 {
                     if (!bracket)
+                    {
                         break;
+                    }
                 }
                 else
                 {

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
index 68222d4..fa59d62 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs
@@ -23,6 +23,7 @@ namespace Apache.Ignite.Core.Impl.Binary
     using System.Diagnostics.CodeAnalysis;
     using System.Linq;
     using System.Reflection;
+    using Apache.Ignite.Core.Binary;
 
     /// <summary>
     /// Resolves types by name.
@@ -37,10 +38,11 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="typeName">Name of the type.</param>
         /// <param name="assemblyName">Optional, name of the assembly.</param>
+        /// <param name="nameMapper">The name mapper.</param>
         /// <returns>
         /// Resolved type.
         /// </returns>
-        public Type ResolveType(string typeName, string assemblyName = null)
+        public Type ResolveType(string typeName, string assemblyName = null, IBinaryNameMapper nameMapper = null)
         {
             Debug.Assert(!string.IsNullOrEmpty(typeName));
 
@@ -55,8 +57,8 @@ namespace Apache.Ignite.Core.Impl.Binary
             var parsedType = TypeNameParser.Parse(typeName);
 
             // Partial names should be resolved by scanning assemblies.
-            return ResolveType(assemblyName, parsedType, AppDomain.CurrentDomain.GetAssemblies())
-                ?? ResolveTypeInReferencedAssemblies(assemblyName, parsedType);
+            return ResolveType(assemblyName, parsedType, AppDomain.CurrentDomain.GetAssemblies(), nameMapper)
+                ?? ResolveTypeInReferencedAssemblies(assemblyName, parsedType, nameMapper);
         }
 
         /// <summary>
@@ -65,12 +67,14 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="assemblyName">Name of the assembly.</param>
         /// <param name="typeName">Name of the type.</param>
         /// <param name="assemblies">Assemblies to look in.</param>
+        /// <param name="nameMapper">The name mapper.</param>
         /// <returns> 
         /// Resolved type. 
         /// </returns>
-        private static Type ResolveType(string assemblyName, TypeNameParser typeName, ICollection<Assembly> assemblies)
+        private static Type ResolveType(string assemblyName, TypeNameParser typeName, ICollection<Assembly> assemblies,
+            IBinaryNameMapper nameMapper)
         {
-            var type = ResolveNonGenericType(assemblyName, typeName.GetFullName(), assemblies);
+            var type = ResolveNonGenericType(assemblyName, typeName.GetNameWithNamespace(), assemblies, nameMapper);
 
             if (type == null)
             {
@@ -79,9 +83,54 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             if (type.IsGenericTypeDefinition && typeName.Generics != null)
             {
-                var genArgs = typeName.Generics.Select(x => ResolveType(assemblyName, x, assemblies)).ToArray();
+                var genArgs = typeName.Generics
+                    .Select(x => ResolveType(assemblyName, x, assemblies, nameMapper)).ToArray();
 
-                return type.MakeGenericType(genArgs);
+                if (genArgs.Any(x => x == null))
+                {
+                    return null;
+                }
+
+                type = type.MakeGenericType(genArgs);
+            }
+
+            return MakeArrayType(type, typeName.GetArray());
+        }
+
+        /// <summary>
+        /// Makes the array type according to spec, e.g. "[,][]".
+        /// </summary>
+        private static Type MakeArrayType(Type type, string arraySpec)
+        {
+            if (arraySpec == null)
+            {
+                return type;
+            }
+
+            int? rank = null;
+
+            foreach (var c in arraySpec)
+            {
+                switch (c)
+                {
+                    case '[':
+                        rank = null;
+                        break;
+
+                    case ',':
+                        rank = rank == null ? 2 : rank + 1;
+                        break;
+
+                    case '*':
+                        rank = 1;
+                        break;
+
+                    case ']':
+                        type = rank == null
+                            ? type.MakeArrayType()
+                            : type.MakeArrayType(rank.Value);
+                        break;
+                }
             }
 
             return type;
@@ -93,8 +142,10 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// <param name="assemblyName">Name of the assembly.</param>
         /// <param name="typeName">Name of the type.</param>
         /// <param name="assemblies">The assemblies.</param>
+        /// <param name="nameMapper">The name mapper.</param>
         /// <returns>Resolved type, or null.</returns>
-        private static Type ResolveNonGenericType(string assemblyName, string typeName, ICollection<Assembly> assemblies)
+        private static Type ResolveNonGenericType(string assemblyName, string typeName, 
+            ICollection<Assembly> assemblies, IBinaryNameMapper nameMapper)
         {
             // Fully-qualified name can be resolved with system mechanism.
             var type = Type.GetType(typeName, false);
@@ -115,15 +166,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 return null;
             }
 
-            // Trim assembly qualification
-            var commaIdx = typeName.IndexOf(',');
-
-            if (commaIdx > 0)
-            {
-                typeName = typeName.Substring(0, commaIdx);
-            }
-
-            return assemblies.Select(a => a.GetType(typeName, false, false)).FirstOrDefault(x => x != null);
+            return assemblies.Select(a => FindType(a, typeName, nameMapper)).FirstOrDefault(x => x != null);
         }
 
         /// <summary>
@@ -131,10 +174,12 @@ namespace Apache.Ignite.Core.Impl.Binary
         /// </summary>
         /// <param name="assemblyName">Name of the assembly.</param>
         /// <param name="typeName">Name of the type.</param>
+        /// <param name="nameMapper">The name mapper.</param>
         /// <returns>
         /// Resolved type.
         /// </returns>
-        private Type ResolveTypeInReferencedAssemblies(string assemblyName, TypeNameParser typeName)
+        private Type ResolveTypeInReferencedAssemblies(string assemblyName, TypeNameParser typeName,
+            IBinaryNameMapper nameMapper)
         {
             ResolveEventHandler resolver = (sender, args) => GetReflectionOnlyAssembly(args.Name);
 
@@ -142,7 +187,8 @@ namespace Apache.Ignite.Core.Impl.Binary
 
             try
             {
-                var result = ResolveType(assemblyName, typeName, GetNotLoadedReferencedAssemblies().ToArray());
+                var result = ResolveType(assemblyName, typeName, GetNotLoadedReferencedAssemblies().ToArray(), 
+                    nameMapper);
 
                 if (result == null)
                     return null;
@@ -150,7 +196,7 @@ namespace Apache.Ignite.Core.Impl.Binary
                 // result is from ReflectionOnly assembly, load it properly into current domain
                 var asm = AppDomain.CurrentDomain.Load(result.Assembly.GetName());
 
-                return asm.GetType(result.FullName);
+                return FindType(asm, result.FullName, nameMapper);
             }
             finally
             {
@@ -215,5 +261,34 @@ namespace Apache.Ignite.Core.Impl.Binary
                     roots.Push(refAsm);
             }
         }
+
+        /// <summary>
+        /// Finds the type within assembly.
+        /// </summary>
+        private static Type FindType(Assembly asm, string typeName, IBinaryNameMapper mapper)
+        {
+            if (mapper == null)
+            {
+                return asm.GetType(typeName);
+            }
+
+            return GetAssemblyTypesSafe(asm).FirstOrDefault(x => mapper.GetTypeName(x.FullName) == typeName);
+        }
+
+        /// <summary>
+        /// Safely gets all assembly types.
+        /// </summary>
+        private static IEnumerable<Type> GetAssemblyTypesSafe(Assembly asm)
+        {
+            try
+            {
+                return asm.GetTypes();
+            }
+            catch (ReflectionTypeLoadException ex)
+            {
+                // Handle the situation where some assembly dependencies are not available.
+                return ex.Types.Where(x => x != null);
+            }
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ba21c46c/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
index f8ff85c..033de7e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Memory/PlatformMemoryStream.cs
@@ -893,7 +893,7 @@ namespace Apache.Ignite.Core.Impl.Memory
         /// <summary>
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// </summary>
-        protected virtual void Dispose(bool disposing)
+        private void Dispose(bool disposing)
         {
             if (disposing)
                 SynchronizeOutput();


[06/13] ignite git commit: IGNITE-5119 Append extra message to exception when unable to determine affinity

Posted by sb...@apache.org.
IGNITE-5119 Append extra message to exception when unable to determine affinity


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

Branch: refs/heads/ignite-5009
Commit: 5dc989624da19f400f69f2ea61cfa1d26659739a
Parents: 8c3ac14
Author: William Do <bl...@gmail.com>
Authored: Mon May 8 11:17:42 2017 -0700
Committer: Denis Magda <dm...@gridgain.com>
Committed: Mon May 8 11:17:42 2017 -0700

----------------------------------------------------------------------
 .../internal/processors/affinity/GridAffinityProcessor.java       | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/5dc98962/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityProcessor.java
index e1b9f64..e57cf54 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/affinity/GridAffinityProcessor.java
@@ -186,7 +186,8 @@ public class GridAffinityProcessor extends GridProcessorAdapter {
             aff = affinityCache(cacheName, ctx.discovery().topologyVersionEx());
 
             if (aff == null)
-                throw new IgniteCheckedException("Failed to get cache affinity.");
+                throw new IgniteCheckedException("Failed to get cache affinity (cache was not started " +
+                        "yet or cache was already stopped): " + cacheName);
         }
 
         return aff.affFunc.partition(aff.affinityKey(key));


[13/13] ignite git commit: ignite-5009

Posted by sb...@apache.org.
ignite-5009


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

Branch: refs/heads/ignite-5009
Commit: 689bdf69bda38b5b4048f1707a00926311c0b13a
Parents: 49b95b4
Author: sboikov <sb...@gridgain.com>
Authored: Wed May 10 17:40:33 2017 +0300
Committer: sboikov <sb...@gridgain.com>
Committed: Wed May 10 17:40:33 2017 +0300

----------------------------------------------------------------------
 .../apache/ignite/internal/processors/cache/GridCacheContext.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/689bdf69/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 1b3b57b..897757a 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
@@ -2043,7 +2043,7 @@ public class GridCacheContext<K, V> implements Externalizable {
      * @return {@code True} if it is possible directly read offheap instead of using {@link GridCacheEntryEx#innerGet}.
      */
     public boolean readNoEntry(IgniteCacheExpiryPolicy expiryPlc, boolean readers) {
-        return !readers && expiryPlc == null;
+        return !config().isOnheapCacheEnabled() && !readers && expiryPlc == null;
     }
 
     /**


[07/13] ignite git commit: master - fixed SELECT (SELECT COUNT(1)) FROM

Posted by sb...@apache.org.
master - fixed SELECT (SELECT COUNT(1)) FROM


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

Branch: refs/heads/ignite-5009
Commit: d10091d6f23e648d413e478b69e9da0f62c18413
Parents: 5dc9896
Author: Sergi Vladykin <se...@gmail.com>
Authored: Tue May 9 06:11:34 2017 +0300
Committer: Sergi Vladykin <se...@gmail.com>
Committed: Tue May 9 06:11:34 2017 +0300

----------------------------------------------------------------------
 .../query/h2/sql/GridSqlQuerySplitter.java      |  7 ++++-
 .../query/IgniteSqlSplitterSelfTest.java        | 30 ++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/d10091d6/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
index b3d54e1..2bac505 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
@@ -1734,13 +1734,18 @@ public class GridSqlQuerySplitter {
     }
 
     /**
-     * @param el Expression.
+     * @param el Expression part in SELECT clause.
      * @return {@code true} If expression contains aggregates.
      */
     private static boolean hasAggregates(GridSqlAst el) {
         if (el instanceof GridSqlAggregateFunction)
             return true;
 
+        // If in SELECT clause we have a subquery expression with aggregate,
+        // we should not split it. Run the whole subquery on MAP stage.
+        if (el instanceof GridSqlQuery)
+            return false;
+
         for (int i = 0; i < el.size(); i++) {
             if (hasAggregates(el.child(i)))
                 return true;

http://git-wip-us.apache.org/repos/asf/ignite/blob/d10091d6/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
index 8e56d36..34101d2 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
@@ -37,6 +37,7 @@ import org.apache.ignite.cache.CacheKeyConfiguration;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CachePeekMode;
 import org.apache.ignite.cache.affinity.Affinity;
+import org.apache.ignite.cache.affinity.AffinityKey;
 import org.apache.ignite.cache.affinity.AffinityKeyMapped;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
@@ -291,6 +292,35 @@ public class IgniteSqlSplitterSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     */
+    public void testSubQueryWithAggregate() {
+        CacheConfiguration ccfg1 = cacheConfig("pers", true,
+            AffinityKey.class, Person2.class);
+
+        IgniteCache<AffinityKey<Integer>, Person2> c1 = ignite(0).getOrCreateCache(ccfg1);
+
+        try {
+            int orgId = 100500;
+
+            c1.put(new AffinityKey<>(1, orgId), new Person2(orgId, "Vasya"));
+            c1.put(new AffinityKey<>(2, orgId), new Person2(orgId, "Another Vasya"));
+
+            List<List<?>> rs = c1.query(new SqlFieldsQuery("select name, " +
+                "(select count(1) from Person2 q where q.orgId = p.orgId) " +
+                "from Person2 p order by name desc")).getAll();
+
+            assertEquals(2, rs.size());
+            assertEquals("Vasya", rs.get(0).get(0));
+            assertEquals(2L, rs.get(0).get(1));
+            assertEquals("Another Vasya", rs.get(1).get(0));
+            assertEquals(2L, rs.get(1).get(1));
+        }
+        finally {
+            c1.destroy();
+        }
+    }
+
+    /**
      * @throws InterruptedException If failed.
      */
     public void testDistributedJoinFromReplicatedCache() throws InterruptedException {


[09/13] ignite git commit: master - Fixed typo.

Posted by sb...@apache.org.
master - Fixed typo.


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

Branch: refs/heads/ignite-5009
Commit: 70db21c2292e4fed918875f003052872e0a73ff8
Parents: b039d05
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Wed May 10 10:35:35 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Wed May 10 10:35:35 2017 +0700

----------------------------------------------------------------------
 .../java/org/apache/ignite/messaging/GridMessagingSelfTest.java  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/70db21c2/modules/core/src/test/java/org/apache/ignite/messaging/GridMessagingSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/messaging/GridMessagingSelfTest.java b/modules/core/src/test/java/org/apache/ignite/messaging/GridMessagingSelfTest.java
index ccfffe9..7541cec 100644
--- a/modules/core/src/test/java/org/apache/ignite/messaging/GridMessagingSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/messaging/GridMessagingSelfTest.java
@@ -51,7 +51,7 @@ import org.apache.ignite.internal.util.typedef.P2;
 import org.apache.ignite.internal.util.typedef.PA;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteFuture;
-import org.apache.ignite.resources.IgniteInstanceResource;;
+import org.apache.ignite.resources.IgniteInstanceResource;
 import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
@@ -1336,4 +1336,4 @@ public class GridMessagingSelfTest extends GridCommonAbstractTest implements Ser
 
         assertEquals(1, MSG_CNT.get());
     }
-}
\ No newline at end of file
+}


[11/13] ignite git commit: GridCacheEntryInfo: removed old code.

Posted by sb...@apache.org.
GridCacheEntryInfo: removed old code.


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

Branch: refs/heads/ignite-5009
Commit: 51069c5ca5cac5c0b7b86ba0146e2c019c578ecc
Parents: 68b6838
Author: sboikov <sb...@gridgain.com>
Authored: Wed May 10 14:04:22 2017 +0300
Committer: sboikov <sb...@gridgain.com>
Committed: Wed May 10 14:04:22 2017 +0300

----------------------------------------------------------------------
 .../processors/cache/GridCacheEntryInfo.java    | 68 +++-----------------
 .../GridDhtPartitionSupplyMessage.java          | 30 +--------
 2 files changed, 12 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/51069c5c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
index e50fbfe..c0e1c55 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
@@ -42,9 +42,6 @@ public class GridCacheEntryInfo implements Message {
     @GridToStringInclude
     private KeyCacheObject key;
 
-    /** Key bytes, set when entry is read from swap and there is no key instance. */
-    private byte[] keyBytes;
-
     /** Cache ID. */
     private int cacheId;
 
@@ -90,20 +87,6 @@ public class GridCacheEntryInfo implements Message {
     }
 
     /**
-     * @param bytes Key bytes.
-     */
-    public void keyBytes(byte[] bytes) {
-        this.keyBytes = bytes;
-    }
-
-    /**
-     * @return Key bytes.
-     */
-    public byte[] keyBytes() {
-        return keyBytes;
-    }
-
-    /**
      * @return Entry key.
      */
     public KeyCacheObject key() {
@@ -230,24 +213,18 @@ public class GridCacheEntryInfo implements Message {
                 writer.incrementState();
 
             case 3:
-                if (!writer.writeByteArray("keyBytes", keyBytes))
-                    return false;
-
-                writer.incrementState();
-
-            case 4:
                 if (!writer.writeLong("ttl", ttl))
                     return false;
 
                 writer.incrementState();
 
-            case 5:
+            case 4:
                 if (!writer.writeMessage("val", val))
                     return false;
 
                 writer.incrementState();
 
-            case 6:
+            case 5:
                 if (!writer.writeMessage("ver", ver))
                     return false;
 
@@ -291,14 +268,6 @@ public class GridCacheEntryInfo implements Message {
                 reader.incrementState();
 
             case 3:
-                keyBytes = reader.readByteArray("keyBytes");
-
-                if (!reader.isLastRead())
-                    return false;
-
-                reader.incrementState();
-
-            case 4:
                 ttl = reader.readLong("ttl");
 
                 if (!reader.isLastRead())
@@ -306,7 +275,7 @@ public class GridCacheEntryInfo implements Message {
 
                 reader.incrementState();
 
-            case 5:
+            case 4:
                 val = reader.readMessage("val");
 
                 if (!reader.isLastRead())
@@ -314,7 +283,7 @@ public class GridCacheEntryInfo implements Message {
 
                 reader.incrementState();
 
-            case 6:
+            case 5:
                 ver = reader.readMessage("ver");
 
                 if (!reader.isLastRead())
@@ -334,7 +303,7 @@ public class GridCacheEntryInfo implements Message {
 
     /** {@inheritDoc} */
     @Override public byte fieldsCount() {
-        return 7;
+        return 6;
     }
 
     /**
@@ -358,13 +327,7 @@ public class GridCacheEntryInfo implements Message {
         if (val != null)
             size += val.valueBytes(cacheObjCtx).length;
 
-        if (key == null) {
-            assert keyBytes != null;
-
-            size += keyBytes.length;
-        }
-        else
-            size += key.valueBytes(cacheObjCtx).length;
+        size += key.valueBytes(cacheObjCtx).length;
 
         return SIZE_OVERHEAD + size;
     }
@@ -374,10 +337,9 @@ public class GridCacheEntryInfo implements Message {
      * @throws IgniteCheckedException In case of error.
      */
     public void marshal(GridCacheContext ctx) throws IgniteCheckedException {
-        assert key != null ^ keyBytes != null;
+        assert key != null;
 
-        if (key != null)
-            key.prepareMarshal(ctx.cacheObjectContext());
+        key.prepareMarshal(ctx.cacheObjectContext());
 
         if (val != null)
             val.prepareMarshal(ctx.cacheObjectContext());
@@ -400,17 +362,7 @@ public class GridCacheEntryInfo implements Message {
      * @throws IgniteCheckedException If unmarshalling failed.
      */
     public void unmarshal(GridCacheContext ctx, ClassLoader clsLdr) throws IgniteCheckedException {
-        if (key == null) {
-            assert keyBytes != null;
-
-            CacheObjectContext cacheObjCtx = ctx.cacheObjectContext();
-
-            Object key0 = ctx.cacheObjects().unmarshal(cacheObjCtx, keyBytes, clsLdr);
-
-            key = ctx.cacheObjects().toCacheKeyObject(cacheObjCtx, ctx, key0, false);
-        }
-        else
-            key.finishUnmarshal(ctx.cacheObjectContext(), clsLdr);
+        key.finishUnmarshal(ctx.cacheObjectContext(), clsLdr);
 
         if (val != null)
             val.finishUnmarshal(ctx.cacheObjectContext(), clsLdr);
@@ -428,4 +380,4 @@ public class GridCacheEntryInfo implements Message {
     @Override public String toString() {
         return S.toString(GridCacheEntryInfo.class, this);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/51069c5c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
index ee461ab..903a7da 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
@@ -206,36 +206,10 @@ public class GridDhtPartitionSupplyMessage extends GridCacheMessage implements G
      * @param ctx Cache context.
      * @throws IgniteCheckedException If failed.
      */
-    void addEntry(int p, GridCacheEntryInfo info, GridCacheContext ctx) throws IgniteCheckedException {
-        assert info != null;
-
-        marshalInfo(info, ctx);
-
-        msgSize += info.marshalledSize(ctx);
-
-        CacheEntryInfoCollection infoCol = infos().get(p);
-
-        if (infoCol == null) {
-            msgSize += 4;
-
-            infos().put(p, infoCol = new CacheEntryInfoCollection());
-
-            infoCol.init();
-        }
-
-        infoCol.add(info);
-    }
-
-    /**
-     * @param p Partition.
-     * @param info Entry to add.
-     * @param ctx Cache context.
-     * @throws IgniteCheckedException If failed.
-     */
     void addEntry0(int p, GridCacheEntryInfo info, GridCacheContext ctx) throws IgniteCheckedException {
         assert info != null;
-        assert (info.key() != null || info.keyBytes() != null);
-        assert info.value() != null;
+        assert info.key() != null : info;
+        assert info.value() != null : info;
 
         // Need to call this method to initialize info properly.
         marshalInfo(info, ctx);


[05/13] ignite git commit: Make TestMemcacheClient#cacheMetrics runnable with Java 8.

Posted by sb...@apache.org.
Make TestMemcacheClient#cacheMetrics runnable with Java 8.


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

Branch: refs/heads/ignite-5009
Commit: 8c3ac1463b7327695d5afe33585cb74732f7ae68
Parents: 825a782
Author: shroman <rs...@yahoo.com>
Authored: Mon May 8 22:32:35 2017 +0900
Committer: shroman <rs...@yahoo.com>
Committed: Mon May 8 22:32:35 2017 +0900

----------------------------------------------------------------------
 .../apache/ignite/internal/processors/rest/TestMemcacheClient.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/8c3ac146/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/TestMemcacheClient.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/TestMemcacheClient.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/TestMemcacheClient.java
index 4a66743..a9a0489 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/TestMemcacheClient.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/TestMemcacheClient.java
@@ -537,7 +537,7 @@ final class TestMemcacheClient {
         Map<String, Long> res = new HashMap<>(raw.size());
 
         for (Response resp : raw)
-            res.put((String)resp.key(), Long.parseLong(String.valueOf(resp.getObject())));
+            res.put((String)resp.key(), Long.parseLong(String.valueOf(resp.<String>getObject())));
 
         return res;
     }


[04/13] ignite git commit: ignite-4760 Added test

Posted by sb...@apache.org.
ignite-4760 Added test


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

Branch: refs/heads/ignite-5009
Commit: 825a78267203117047bda9b3de1c87cb085806de
Parents: ba21c46
Author: vadopolski <vo...@gmail.com>
Authored: Sun May 7 12:02:41 2017 +0300
Committer: sboikov <sb...@gridgain.com>
Committed: Sun May 7 12:02:41 2017 +0300

----------------------------------------------------------------------
 .../cache/hibernate/HibernateKeyWrapper.java    |   7 +
 .../HibernateL2CacheStrategySelfTest.java       | 597 +++++++++++++++++++
 .../testsuites/IgniteHibernateTestSuite.java    |   2 +
 .../hibernate/HibernateL2CacheSelfTest.java     |   2 +-
 .../HibernateL2CacheStrategySelfTest.java       | 569 ++++++++++++++++++
 .../testsuites/IgniteHibernate5TestSuite.java   |   2 +
 6 files changed, 1178 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/825a7826/modules/hibernate-4.2/src/main/java/org/apache/ignite/cache/hibernate/HibernateKeyWrapper.java
----------------------------------------------------------------------
diff --git a/modules/hibernate-4.2/src/main/java/org/apache/ignite/cache/hibernate/HibernateKeyWrapper.java b/modules/hibernate-4.2/src/main/java/org/apache/ignite/cache/hibernate/HibernateKeyWrapper.java
index 64de395..22695cc 100644
--- a/modules/hibernate-4.2/src/main/java/org/apache/ignite/cache/hibernate/HibernateKeyWrapper.java
+++ b/modules/hibernate-4.2/src/main/java/org/apache/ignite/cache/hibernate/HibernateKeyWrapper.java
@@ -44,6 +44,13 @@ public class HibernateKeyWrapper implements Serializable {
         this.tenantId = tenantId;
     }
 
+    /**
+     * @return Key.
+     */
+    Object id() {
+        return key;
+    }
+
     /** {@inheritDoc} */
     @Override public boolean equals(Object o) {
         if (this == o) return true;

http://git-wip-us.apache.org/repos/asf/ignite/blob/825a7826/modules/hibernate-4.2/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/hibernate-4.2/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java b/modules/hibernate-4.2/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java
new file mode 100644
index 0000000..48a48dc
--- /dev/null
+++ b/modules/hibernate-4.2/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java
@@ -0,0 +1,597 @@
+/*
+ * 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.cache.hibernate;
+
+import java.util.HashMap;
+import java.util.List;
+import javax.cache.Cache;
+import javax.persistence.Cacheable;
+import javax.persistence.Id;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.hamcrest.core.Is;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cache.spi.access.AccessType;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.service.ServiceRegistryBuilder;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.hibernate.HibernateAccessStrategyFactory.DFLT_ACCESS_TYPE_PROPERTY;
+import static org.apache.ignite.cache.hibernate.HibernateAccessStrategyFactory.IGNITE_INSTANCE_NAME_PROPERTY;
+import static org.apache.ignite.cache.hibernate.HibernateAccessStrategyFactory.REGION_CACHE_PROPERTY;
+import static org.hibernate.cfg.AvailableSettings.CACHE_REGION_FACTORY;
+import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
+import static org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO;
+import static org.hibernate.cfg.AvailableSettings.RELEASE_CONNECTIONS;
+import static org.hibernate.cfg.AvailableSettings.USE_QUERY_CACHE;
+import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
+import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests Hibernate L2 cache configuration.
+ */
+@SuppressWarnings("unchecked")
+public class HibernateL2CacheStrategySelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final String ENTITY1_NAME = Entity1.class.getName();
+
+    /** */
+    private static final String ENTITY2_NAME = Entity2.class.getName();
+
+    /** */
+    private static final String ENTITY3_NAME = Entity3.class.getName();
+
+    /** */
+    private static final String ENTITY4_NAME = Entity4.class.getName();
+
+    /** */
+    private static final String TIMESTAMP_CACHE = "org.hibernate.cache.spi.UpdateTimestampsCache";
+
+    /** */
+    private static final String QUERY_CACHE = "org.hibernate.cache.internal.StandardQueryCache";
+
+    /** */
+    private static final String CONNECTION_URL = "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1";
+
+    /** */
+    private SessionFactory sesFactory1;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrid(0);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        for (IgniteCacheProxy<?, ?> cache : ((IgniteKernal)grid(0)).caches())
+            cache.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(new TcpDiscoveryVmIpFinder(true));
+
+        cfg.setCacheConfiguration(cacheConfiguration(ENTITY3_NAME),
+            cacheConfiguration(ENTITY4_NAME),
+            cacheConfiguration("cache1"),
+            cacheConfiguration("cache2"),
+            cacheConfiguration(TIMESTAMP_CACHE),
+            cacheConfiguration(QUERY_CACHE));
+
+        return cfg;
+    }
+
+    /**
+     * @param cacheName Cache name.
+     * @return Cache configuration.
+     */
+    private CacheConfiguration cacheConfiguration(String cacheName) {
+        CacheConfiguration cfg = new CacheConfiguration();
+
+        cfg.setName(cacheName);
+        cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(TRANSACTIONAL);
+
+        return cfg;
+    }
+
+    /**
+     * @param accessType Cache access type.
+     * @param igniteInstanceName Ignite instance name.
+     * @return Hibernate configuration.
+     */
+    private Configuration hibernateConfiguration(AccessType accessType, String igniteInstanceName) {
+        Configuration cfg = new Configuration();
+
+        cfg.addAnnotatedClass(Entity1.class);
+        cfg.addAnnotatedClass(Entity2.class);
+        cfg.addAnnotatedClass(Entity3.class);
+        cfg.addAnnotatedClass(Entity4.class);
+
+        cfg.setCacheConcurrencyStrategy(ENTITY1_NAME, accessType.getExternalName());
+        cfg.setCacheConcurrencyStrategy(ENTITY2_NAME, accessType.getExternalName());
+        cfg.setCacheConcurrencyStrategy(ENTITY3_NAME, accessType.getExternalName());
+        cfg.setCacheConcurrencyStrategy(ENTITY4_NAME, accessType.getExternalName());
+
+        cfg.setProperty(DFLT_ACCESS_TYPE_PROPERTY, accessType.name());
+
+        cfg.setProperty(HBM2DDL_AUTO, "create");
+
+        cfg.setProperty(GENERATE_STATISTICS, "true");
+
+        cfg.setProperty(USE_SECOND_LEVEL_CACHE, "true");
+
+        cfg.setProperty(USE_QUERY_CACHE, "true");
+
+        cfg.setProperty(CACHE_REGION_FACTORY, HibernateRegionFactory.class.getName());
+
+        cfg.setProperty(RELEASE_CONNECTIONS, "on_close");
+
+        cfg.setProperty(USE_STRUCTURED_CACHE, "true");
+
+        cfg.setProperty(IGNITE_INSTANCE_NAME_PROPERTY, igniteInstanceName);
+
+        cfg.setProperty(REGION_CACHE_PROPERTY + ENTITY1_NAME, "cache1");
+        cfg.setProperty(REGION_CACHE_PROPERTY + ENTITY2_NAME, "cache2");
+        cfg.setProperty(REGION_CACHE_PROPERTY + TIMESTAMP_CACHE, TIMESTAMP_CACHE);
+        cfg.setProperty(REGION_CACHE_PROPERTY + QUERY_CACHE, QUERY_CACHE);
+
+        return cfg;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testEntityCacheReadWrite() throws Exception {
+        for (AccessType accessType : new AccessType[]{AccessType.READ_WRITE, AccessType.NONSTRICT_READ_WRITE})
+            testEntityCacheReadWrite(accessType);
+    }
+
+    /**
+     * @param accessType Cache access type.
+     * @throws Exception If failed.
+     */
+    private void testEntityCacheReadWrite(AccessType accessType) throws Exception {
+        log.info("Test access type: " + accessType);
+
+        sesFactory1 = startHibernate(accessType, getTestIgniteInstanceName(0));
+
+        try {
+            // 1 Adding.
+            Session ses = sesFactory1.openSession();
+
+            try {
+                Transaction tr = ses.beginTransaction();
+
+                ses.save(new Entity1(1, "entity-1#name-1"));
+                ses.save(new Entity2(1, "entity-2#name-1"));
+
+                tr.commit();
+            }
+            finally {
+                ses.close();
+            }
+
+            loadEntities(sesFactory1);
+
+            assertEquals(1, grid(0).cache("cache1").size());
+            assertEquals(1, grid(0).cache("cache2").size());
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1"));
+
+            // 2. Updating and adding.
+            ses = sesFactory1.openSession();
+
+            try {
+                Transaction tx = ses.beginTransaction();
+
+                Entity1 e1 = (Entity1)ses.load(Entity1.class, 1);
+
+                e1.setName("entity-1#name-1#UPDATED-1");
+
+                ses.update(e1);
+
+                ses.save(new Entity2(2, "entity-2#name-2#ADDED"));
+
+                tx.commit();
+            }
+            finally {
+                ses.close();
+            }
+
+            loadEntities(sesFactory1);
+
+            assertEquals(1, grid(0).cache("cache1").size());
+            assertEquals(2, grid(0).cache("cache2").size());
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1#UPDATED-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 2), Is.is("entity-2#name-2#ADDED"));
+
+            // 3. Updating, adding, updating.
+            ses = sesFactory1.openSession();
+
+            try {
+                Transaction tx = ses.beginTransaction();
+
+                Entity2 e2_1 = (Entity2)ses.load(Entity2.class, 1);
+
+                e2_1.setName("entity-2#name-1#UPDATED-1");
+
+                ses.update(e2_1);
+
+                ses.save(new Entity1(2, "entity-1#name-2#ADDED"));
+
+                Entity1 e1_1 = (Entity1)ses.load(Entity1.class, 1);
+
+                e1_1.setName("entity-1#name-1#UPDATED-2");
+
+                ses.update(e1_1);
+
+                tx.commit();
+
+            }
+            finally {
+                ses.close();
+            }
+
+            loadEntities(sesFactory1);
+
+            assertEquals(2, grid(0).cache("cache1").size());
+            assertEquals(2, grid(0).cache("cache2").size());
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1#UPDATED-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 2), Is.is("entity-1#name-2#ADDED"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1#UPDATED-2"));
+
+            ses = sesFactory1.openSession();
+
+            sesFactory1.getStatistics().logSummary();
+
+            ses.close();
+        }
+        finally {
+            cleanup();
+        }
+    }
+
+    /**
+     * @param sesFactory Session factory.
+     */
+    private void loadEntities(SessionFactory sesFactory) {
+        Session ses = sesFactory.openSession();
+
+        try {
+            List<Entity1> list1 = ses.createCriteria(ENTITY1_NAME).list();
+
+            for (Entity1 e1 : list1)
+                assertNotNull(e1.getName());
+
+            List<Entity2> list2 = ses.createCriteria(ENTITY2_NAME).list();
+
+            for (Entity2 e2 : list2)
+                assertNotNull(e2.getName());
+        }
+        finally {
+            ses.close();
+        }
+    }
+
+    /**
+     * @param sesFactory Session Factory.
+     * @param regionName Region Name.
+     * @param id Id.
+     * @return Entity Name.
+     */
+    private String getEntityNameFromRegion(SessionFactory sesFactory, String regionName, int id) {
+        Session ses = sesFactory.openSession();
+
+        try {
+            for (Cache.Entry<Object, Object> entry : grid(0).cache(regionName)) {
+                if (((HibernateKeyWrapper)entry.getKey()).id().equals(id))
+                    return (String) ((HashMap) entry.getValue()).get("name");
+            }
+
+            return null;
+        }
+        finally {
+            ses.close();
+        }
+    }
+
+    /**
+     * @param accessType Cache access typr.
+     * @param igniteInstanceName Name of the grid providing caches.
+     * @return Session factory.
+     */
+    private SessionFactory startHibernate(AccessType accessType, String igniteInstanceName) {
+        Configuration cfg = hibernateConfiguration(accessType, igniteInstanceName);
+
+        ServiceRegistryBuilder builder = new ServiceRegistryBuilder();
+
+        builder.applySetting("hibernate.connection.url", CONNECTION_URL);
+        builder.applySetting("hibernate.show_sql", false);
+
+        return cfg.buildSessionFactory(builder.buildServiceRegistry());
+    }
+
+    /**
+     * Test Hibernate entity1.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity1 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity1() {
+            // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        Entity1(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Test Hibernate entity2.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity2 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity2() {
+           // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        Entity2(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Test Hibernate entity3.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity3 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity3() {
+            // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        public Entity3(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Test Hibernate entity4.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity4 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity4() {
+            // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        public Entity4(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Closes session factories and clears data from caches.
+     *
+     * @throws Exception If failed.
+     */
+    private void cleanup() throws Exception {
+        if (sesFactory1 != null)
+            sesFactory1.close();
+
+        sesFactory1 = null;
+
+        for (IgniteCacheProxy<?, ?> cache : ((IgniteKernal)grid(0)).caches())
+            cache.clear();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/825a7826/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java b/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
index 99fea56..22d870d 100644
--- a/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
+++ b/modules/hibernate-4.2/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
@@ -20,6 +20,7 @@ package org.apache.ignite.testsuites;
 import junit.framework.TestSuite;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheConfigurationSelfTest;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheSelfTest;
+import org.apache.ignite.cache.hibernate.HibernateL2CacheStrategySelfTest;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheTransactionalSelfTest;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheTransactionalUseSyncSelfTest;
 import org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreNodeRestartTest;
@@ -43,6 +44,7 @@ public class IgniteHibernateTestSuite extends TestSuite {
         suite.addTestSuite(HibernateL2CacheTransactionalSelfTest.class);
         suite.addTestSuite(HibernateL2CacheTransactionalUseSyncSelfTest.class);
         suite.addTestSuite(HibernateL2CacheConfigurationSelfTest.class);
+        suite.addTestSuite(HibernateL2CacheStrategySelfTest.class);
 
         suite.addTestSuite(CacheHibernateBlobStoreSelfTest.class);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/825a7826/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheSelfTest.java b/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheSelfTest.java
index f227af1..84883a0 100644
--- a/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheSelfTest.java
+++ b/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheSelfTest.java
@@ -1906,7 +1906,7 @@ public class HibernateL2CacheSelfTest extends GridCommonAbstractTest {
         }
 
         for (org.hibernate.mapping.Collection collectionBinding : metadata.getCollectionBindings())
-            collectionBinding.setCacheConcurrencyStrategy( accessType.getExternalName() );
+            collectionBinding.setCacheConcurrencyStrategy(accessType.getExternalName() );
 
         return metadata.buildSessionFactory();
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/825a7826/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java b/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java
new file mode 100644
index 0000000..af71981
--- /dev/null
+++ b/modules/hibernate-5.1/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java
@@ -0,0 +1,569 @@
+/*
+ * 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.cache.hibernate;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.cache.Cache;
+import javax.persistence.Cacheable;
+import javax.persistence.Id;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.hamcrest.core.Is;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.boot.Metadata;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cache.spi.access.AccessType;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.RootClass;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.hibernate.HibernateAccessStrategyFactory.REGION_CACHE_PROPERTY;
+import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests Hibernate L2 cache configuration.
+ */
+@SuppressWarnings("unchecked")
+public class HibernateL2CacheStrategySelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final String ENTITY1_NAME = Entity1.class.getName();
+
+    /** */
+    private static final String ENTITY2_NAME = Entity2.class.getName();
+
+    /** */
+    private static final String ENTITY3_NAME = Entity3.class.getName();
+
+    /** */
+    private static final String ENTITY4_NAME = Entity4.class.getName();
+
+    /** */
+    private static final String TIMESTAMP_CACHE = "org.hibernate.cache.spi.UpdateTimestampsCache";
+
+    /** */
+    private static final String QUERY_CACHE = "org.hibernate.cache.internal.StandardQueryCache";
+
+    /** */
+    private static final String CONNECTION_URL = "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1";
+
+    /** */
+    private SessionFactory sesFactory1;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrid(0);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        for (IgniteCacheProxy<?, ?> cache : ((IgniteKernal)grid(0)).caches())
+            cache.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(new TcpDiscoveryVmIpFinder(true));
+
+        cfg.setCacheConfiguration(cacheConfiguration(ENTITY3_NAME),
+            cacheConfiguration(ENTITY4_NAME),
+            cacheConfiguration("cache1"),
+            cacheConfiguration("cache2"),
+            cacheConfiguration(TIMESTAMP_CACHE),
+            cacheConfiguration(QUERY_CACHE));
+
+        return cfg;
+    }
+
+    /**
+     * @param cacheName Cache name.
+     * @return Cache configuration.
+     */
+    private CacheConfiguration cacheConfiguration(String cacheName) {
+        CacheConfiguration cfg = new CacheConfiguration();
+
+        cfg.setName(cacheName);
+        cfg.setCacheMode(PARTITIONED);
+        cfg.setAtomicityMode(TRANSACTIONAL);
+
+        return cfg;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testEntityCacheReadWrite() throws Exception {
+        for (AccessType accessType : new AccessType[]{AccessType.READ_WRITE, AccessType.NONSTRICT_READ_WRITE})
+            testEntityCacheReadWrite(accessType);
+    }
+
+    /**
+     * @param accessType Cache access type.
+     * @throws Exception If failed.
+     */
+    private void testEntityCacheReadWrite(AccessType accessType) throws Exception {
+        log.info("Test access type: " + accessType);
+
+        sesFactory1 = startHibernate(accessType, getTestIgniteInstanceName(0));
+
+        try {
+            // 1 Adding.
+            Session ses = sesFactory1.openSession();
+
+            try {
+                Transaction tr = ses.beginTransaction();
+
+                ses.save(new Entity1(1, "entity-1#name-1"));
+                ses.save(new Entity2(1, "entity-2#name-1"));
+
+                tr.commit();
+            }
+            finally {
+                ses.close();
+            }
+
+            loadEntities(sesFactory1);
+
+            assertEquals(1, grid(0).cache("cache1").size());
+            assertEquals(1, grid(0).cache("cache2").size());
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1"));
+
+            // 2. Updating and adding.
+            ses = sesFactory1.openSession();
+
+            try {
+                Transaction tx = ses.beginTransaction();
+
+                Entity1 e1 = (Entity1)ses.load(Entity1.class, 1);
+
+                e1.setName("entity-1#name-1#UPDATED-1");
+
+                ses.update(e1);
+
+                ses.save(new Entity2(2, "entity-2#name-2#ADDED"));
+
+                tx.commit();
+            }
+            finally {
+                ses.close();
+            }
+
+            loadEntities(sesFactory1);
+
+            assertEquals(1, grid(0).cache("cache1").size());
+            assertEquals(2, grid(0).cache("cache2").size());
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1#UPDATED-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 2), Is.is("entity-2#name-2#ADDED"));
+
+            // 3. Updating, adding, updating.
+            ses = sesFactory1.openSession();
+
+            try {
+                Transaction tx = ses.beginTransaction();
+
+                Entity2 e2_1 = (Entity2)ses.load(Entity2.class, 1);
+
+                e2_1.setName("entity-2#name-1#UPDATED-1");
+
+                ses.update(e2_1);
+
+                ses.save(new Entity1(2, "entity-1#name-2#ADDED"));
+
+                Entity1 e1_1 = (Entity1)ses.load(Entity1.class, 1);
+
+                e1_1.setName("entity-1#name-1#UPDATED-2");
+
+                ses.update(e1_1);
+
+                tx.commit();
+
+            }
+            finally {
+                ses.close();
+            }
+
+            loadEntities(sesFactory1);
+
+            assertEquals(2, grid(0).cache("cache1").size());
+            assertEquals(2, grid(0).cache("cache2").size());
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1#UPDATED-1"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 2), Is.is("entity-1#name-2#ADDED"));
+            assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1#UPDATED-2"));
+
+            ses = sesFactory1.openSession();
+
+            sesFactory1.getStatistics().logSummary();
+
+            ses.close();
+        }
+        finally {
+            cleanup();
+        }
+    }
+
+    /**
+     * @param sesFactory Session factory.
+     */
+    private void loadEntities(SessionFactory sesFactory) {
+        Session ses = sesFactory.openSession();
+
+        try {
+            List<Entity1> list1 = ses.createCriteria(ENTITY1_NAME).list();
+
+            for (Entity1 e1 : list1)
+                assertNotNull(e1.getName());
+
+            List<Entity2> list2 = ses.createCriteria(ENTITY2_NAME).list();
+
+            for (Entity2 e2 : list2)
+                assertNotNull(e2.getName());
+        }
+        finally {
+            ses.close();
+        }
+    }
+
+    /**
+     * @param sesFactory Session Factory.
+     * @param regionName Region Name.
+     * @param id Id.
+     * @return Entity Name.
+     */
+    private String getEntityNameFromRegion(SessionFactory sesFactory, String regionName, int id) {
+        Session ses = sesFactory.openSession();
+
+        try {
+            for (Cache.Entry<Object, Object> entry : grid(0).cache(regionName)) {
+                if (((HibernateKeyWrapper)entry.getKey()).id().equals(id))
+                    return (String) ((HashMap) entry.getValue()).get("name");
+            }
+
+            return null;
+        }
+        finally {
+            ses.close();
+        }
+    }
+
+    /**
+     * @param accessType Cache access typr.
+     * @param igniteInstanceName Name of the grid providing caches.
+     * @return Session factory.
+     */
+    private SessionFactory startHibernate(AccessType accessType, String igniteInstanceName) {
+        StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder();
+
+        builder.applySetting("hibernate.connection.url", CONNECTION_URL);
+
+        for (Map.Entry<String, String> e : HibernateL2CacheSelfTest.hibernateProperties(igniteInstanceName, accessType.name()).entrySet())
+            builder.applySetting(e.getKey(), e.getValue());
+
+        builder.applySetting(USE_STRUCTURED_CACHE, "true");
+        builder.applySetting(REGION_CACHE_PROPERTY + ENTITY1_NAME, "cache1");
+        builder.applySetting(REGION_CACHE_PROPERTY + ENTITY2_NAME, "cache2");
+        builder.applySetting(REGION_CACHE_PROPERTY + TIMESTAMP_CACHE, TIMESTAMP_CACHE);
+        builder.applySetting(REGION_CACHE_PROPERTY + QUERY_CACHE, QUERY_CACHE);
+
+        MetadataSources metadataSources = new MetadataSources(builder.build());
+
+        metadataSources.addAnnotatedClass(Entity1.class);
+        metadataSources.addAnnotatedClass(Entity2.class);
+        metadataSources.addAnnotatedClass(Entity3.class);
+        metadataSources.addAnnotatedClass(Entity4.class);
+
+        Metadata metadata = metadataSources.buildMetadata();
+
+        for (PersistentClass entityBinding : metadata.getEntityBindings()) {
+            if (!entityBinding.isInherited())
+                ((RootClass)entityBinding).setCacheConcurrencyStrategy(accessType.getExternalName());
+        }
+
+        return metadata.buildSessionFactory();
+    }
+
+    /**
+     * Test Hibernate entity1.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity1 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity1() {
+            // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        Entity1(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Test Hibernate entity2.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity2 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity2() {
+           // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        Entity2(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Test Hibernate entity3.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity3 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity3() {
+            // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        public Entity3(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Test Hibernate entity4.
+     */
+    @javax.persistence.Entity
+    @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"})
+    @Cacheable
+    public static class Entity4 {
+        /** */
+        private int id;
+
+        /** */
+        private String name;
+
+        /**
+         *
+         */
+        public Entity4() {
+            // No-op.
+        }
+
+        /**
+         * @param id ID.
+         * @param name Name.
+         */
+        public Entity4(int id, String name) {
+            this.id = id;
+            this.name = name;
+        }
+
+        /**
+         * @return ID.
+         */
+        @Id
+        public int getId() {
+            return id;
+        }
+
+        /**
+         * @param id ID.
+         */
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Closes session factories and clears data from caches.
+     *
+     * @throws Exception If failed.
+     */
+    private void cleanup() throws Exception {
+        if (sesFactory1 != null)
+            sesFactory1.close();
+
+        sesFactory1 = null;
+
+        for (IgniteCacheProxy<?, ?> cache : ((IgniteKernal)grid(0)).caches())
+            cache.clear();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/825a7826/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteHibernate5TestSuite.java
----------------------------------------------------------------------
diff --git a/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteHibernate5TestSuite.java b/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteHibernate5TestSuite.java
index 3d7c4ee..1e06329 100644
--- a/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteHibernate5TestSuite.java
+++ b/modules/hibernate-5.1/src/test/java/org/apache/ignite/testsuites/IgniteHibernate5TestSuite.java
@@ -20,6 +20,7 @@ package org.apache.ignite.testsuites;
 import junit.framework.TestSuite;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheConfigurationSelfTest;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheSelfTest;
+import org.apache.ignite.cache.hibernate.HibernateL2CacheStrategySelfTest;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheTransactionalSelfTest;
 import org.apache.ignite.cache.hibernate.HibernateL2CacheTransactionalUseSyncSelfTest;
 import org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreNodeRestartTest;
@@ -43,6 +44,7 @@ public class IgniteHibernate5TestSuite extends TestSuite {
         suite.addTestSuite(HibernateL2CacheTransactionalSelfTest.class);
         suite.addTestSuite(HibernateL2CacheTransactionalUseSyncSelfTest.class);
         suite.addTestSuite(HibernateL2CacheConfigurationSelfTest.class);
+        suite.addTestSuite(HibernateL2CacheStrategySelfTest.class);
 
         suite.addTestSuite(CacheHibernateBlobStoreSelfTest.class);
 


[12/13] ignite git commit: Merge remote-tracking branch 'remotes/origin/master' into ignite-5009

Posted by sb...@apache.org.
Merge remote-tracking branch 'remotes/origin/master' into ignite-5009


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

Branch: refs/heads/ignite-5009
Commit: 49b95b42671c5a765e54a2d3ed24c9a0a34b139b
Parents: 61021b1 51069c5
Author: sboikov <sb...@gridgain.com>
Authored: Wed May 10 17:39:13 2017 +0300
Committer: sboikov <sb...@gridgain.com>
Committed: Wed May 10 17:39:13 2017 +0300

----------------------------------------------------------------------
 .../processors/rest/TestMemcacheClient.java     |   2 +-
 .../apache/ignite/IgniteSystemProperties.java   |   3 +
 .../affinity/GridAffinityProcessor.java         |   3 +-
 .../cache/DynamicCacheChangeBatch.java          |  17 +
 .../processors/cache/GridCacheEntryInfo.java    |  68 +--
 .../processors/cache/GridCacheProcessor.java    |  23 +-
 .../GridDhtPartitionSupplyMessage.java          |  30 +-
 .../processors/odbc/OdbcNioListener.java        | 112 +++-
 .../internal/processors/odbc/OdbcUtils.java     |   3 -
 .../odbc/SqlListenerHandshakeRequest.java       |  83 ---
 .../odbc/SqlListenerHandshakeResult.java        |  73 ---
 .../odbc/SqlListenerProtocolVersion.java        | 110 ++--
 .../processors/odbc/odbc/OdbcMessageParser.java |  43 --
 .../odbc/odbc/OdbcRequestHandler.java           |  65 +-
 .../ignite/spi/discovery/tcp/ClientImpl.java    |  21 +-
 .../ignite/spi/discovery/tcp/ServerImpl.java    |   2 +
 .../spi/discovery/tcp/TcpDiscoverySpi.java      |   7 +
 .../cache/distributed/CacheStartOnJoinTest.java | 250 ++++++++
 .../ignite/messaging/GridMessagingSelfTest.java |   4 +-
 .../testframework/junits/GridAbstractTest.java  |  12 +
 .../testsuites/IgniteCacheTestSuite4.java       |   2 +
 .../cache/hibernate/HibernateKeyWrapper.java    |   7 +
 .../HibernateL2CacheStrategySelfTest.java       | 597 +++++++++++++++++++
 .../testsuites/IgniteHibernateTestSuite.java    |   2 +
 .../hibernate/HibernateL2CacheSelfTest.java     |   2 +-
 .../HibernateL2CacheStrategySelfTest.java       | 569 ++++++++++++++++++
 .../testsuites/IgniteHibernate5TestSuite.java   |   2 +
 .../query/h2/DmlStatementsProcessor.java        |   9 +
 .../processors/query/h2/IgniteH2Indexing.java   |   6 +-
 .../query/h2/sql/GridSqlQuerySplitter.java      |   7 +-
 ...niteCacheAbstractInsertSqlQuerySelfTest.java |   3 +-
 .../IgniteCacheInsertSqlQuerySelfTest.java      |  22 +
 .../query/IgniteSqlSplitterSelfTest.java        |  30 +
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   1 +
 .../project/vs/odbc-test.vcxproj.filters        |   4 +
 .../cpp/odbc-test/src/configuration_test.cpp    |  39 +-
 .../cpp/odbc-test/src/queries_test.cpp          |   4 +-
 .../cpp/odbc/include/ignite/odbc/message.h      |  45 +-
 .../odbc/include/ignite/odbc/protocol_version.h | 101 ++--
 .../src/system/ui/dsn_configuration_window.cpp  |  10 +-
 modules/platforms/cpp/odbc/src/connection.cpp   |  35 +-
 .../platforms/cpp/odbc/src/protocol_version.cpp | 136 +++--
 .../Apache.Ignite.Core.Tests.csproj             |   1 +
 .../Binary/BinaryDynamicRegistrationTest.cs     |  40 ++
 .../Binary/BinaryNameMapperTest.cs              |   7 +
 .../Binary/TypeNameParserTest.cs                |  93 ++-
 .../Binary/TypeResolverTest.cs                  | 104 ++++
 .../Cache/Query/CacheQueriesTest.cs             |   5 +-
 .../Apache.Ignite.Core.Tests/DeploymentTest.cs  |   1 +
 .../Examples/ExamplesTest.cs                    |   5 +-
 .../Binary/BinaryBasicNameMapper.cs             |   6 +-
 .../Impl/Binary/BinaryProcessor.cs              |  15 +-
 .../Impl/Binary/BinaryReader.cs                 |   6 +-
 .../Impl/Binary/Marshaller.cs                   |  18 +-
 .../Impl/Binary/TypeNameParser.cs               |  31 +-
 .../Impl/Binary/TypeResolver.cs                 | 115 +++-
 .../Impl/Memory/PlatformMemoryStream.cs         |   2 +-
 57 files changed, 2406 insertions(+), 607 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/49b95b42/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
----------------------------------------------------------------------