You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by nt...@apache.org on 2017/08/15 18:00:02 UTC

[01/29] ignite git commit: IGNITE-4800: Lucene query may fails with NPE. This closes #2315.

Repository: ignite
Updated Branches:
  refs/heads/ignite-5947 [created] 49bc7fb41


IGNITE-4800: Lucene query may fails with NPE. This closes #2315.


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

Branch: refs/heads/ignite-5947
Commit: 1e08c3fb5c02ec8acafd71b50b6ad3b749259f1a
Parents: a07d7b9
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Mon Jul 31 14:14:56 2017 +0300
Committer: Andrey V. Mashenkov <an...@gmail.com>
Committed: Mon Jul 31 17:24:26 2017 +0300

----------------------------------------------------------------------
 .../query/h2/opt/GridLuceneDirectory.java       | 64 +++++++++++---
 .../processors/query/h2/opt/GridLuceneFile.java | 91 +++++++++++++++-----
 .../query/h2/opt/GridLuceneIndex.java           |  3 +-
 .../query/h2/opt/GridLuceneInputStream.java     | 42 ++++++---
 .../query/h2/opt/GridLuceneOutputStream.java    | 18 +++-
 ...teCacheFullTextQueryNodeJoiningSelfTest.java |  4 +
 .../IgniteCacheQuerySelfTestSuite.java          |  2 +
 7 files changed, 178 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneDirectory.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneDirectory.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneDirectory.java
index ff20987..3ac9641 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneDirectory.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneDirectory.java
@@ -21,22 +21,27 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
+import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.lucene.store.BaseDirectory;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.IOContext;
 import org.apache.lucene.store.IndexInput;
 import org.apache.lucene.store.IndexOutput;
+import org.apache.lucene.util.Accountable;
+import org.apache.lucene.util.Accountables;
 
 /**
  * A memory-resident {@link Directory} implementation.
  */
-public class GridLuceneDirectory extends BaseDirectory {
+public class GridLuceneDirectory extends BaseDirectory implements Accountable {
     /** */
     protected final Map<String, GridLuceneFile> fileMap = new ConcurrentHashMap<>();
 
@@ -51,7 +56,7 @@ public class GridLuceneDirectory extends BaseDirectory {
      *
      * @param mem Memory.
      */
-    public GridLuceneDirectory(GridUnsafeMemory mem) {
+    GridLuceneDirectory(GridUnsafeMemory mem) {
         super(new GridLuceneLockFactory());
 
         this.mem = mem;
@@ -64,10 +69,7 @@ public class GridLuceneDirectory extends BaseDirectory {
         // and the code below is resilient to map changes during the array population.
         Set<String> fileNames = fileMap.keySet();
 
-        List<String> names = new ArrayList<>(fileNames.size());
-
-        for (String name : fileNames)
-            names.add(name);
+        List<String> names = new ArrayList<>(fileNames);
 
         return names.toArray(new String[names.size()]);
     }
@@ -82,6 +84,7 @@ public class GridLuceneDirectory extends BaseDirectory {
             throw new FileNotFoundException(source);
 
         fileMap.put(dest, file);
+
         fileMap.remove(source);
     }
 
@@ -101,21 +104,25 @@ public class GridLuceneDirectory extends BaseDirectory {
     @Override public void deleteFile(String name) throws IOException {
         ensureOpen();
 
-        doDeleteFile(name);
+        doDeleteFile(name, false);
     }
 
     /**
      * Deletes file.
      *
      * @param name File name.
+     * @param onClose If on close directory;
      * @throws IOException If failed.
      */
-    private void doDeleteFile(String name) throws IOException {
+    private void doDeleteFile(String name, boolean onClose) throws IOException {
         GridLuceneFile file = fileMap.remove(name);
 
         if (file != null) {
             file.delete();
 
+            // All files should be closed when Directory is closing.
+            assert !onClose || !file.hasRefs() : "Possible memory leak, resource is not closed: " + file.toString();
+
             sizeInBytes.addAndGet(-file.getSizeInBytes());
         }
         else
@@ -128,7 +135,10 @@ public class GridLuceneDirectory extends BaseDirectory {
 
         GridLuceneFile file = newRAMFile();
 
-        GridLuceneFile existing = fileMap.remove(name);
+        // Lock for using in stream. Will be unlocked on stream closing.
+        file.lockRef();
+
+        GridLuceneFile existing = fileMap.put(name, file);
 
         if (existing != null) {
             sizeInBytes.addAndGet(-existing.getSizeInBytes());
@@ -136,8 +146,6 @@ public class GridLuceneDirectory extends BaseDirectory {
             existing.delete();
         }
 
-        fileMap.put(name, file);
-
         return new GridLuceneOutputStream(file);
     }
 
@@ -165,6 +173,16 @@ public class GridLuceneDirectory extends BaseDirectory {
         if (file == null)
             throw new FileNotFoundException(name);
 
+        // Lock for using in stream. Will be unlocked on stream closing.
+        file.lockRef();
+
+        if (!fileMap.containsKey(name)) {
+            // Unblock for deferred delete.
+            file.releaseRef();
+
+            throw new FileNotFoundException(name);
+        }
+
         return new GridLuceneInputStream(name, file);
     }
 
@@ -172,16 +190,36 @@ public class GridLuceneDirectory extends BaseDirectory {
     @Override public void close() {
         isOpen = false;
 
+        IgniteException errs = null;
+
         for (String fileName : fileMap.keySet()) {
             try {
-                doDeleteFile(fileName);
+                doDeleteFile(fileName, true);
             }
             catch (IOException e) {
-                throw new IllegalStateException(e);
+                if (errs == null)
+                    errs = new IgniteException("Error closing index directory.");
+
+                errs.addSuppressed(e);
             }
         }
 
         assert fileMap.isEmpty();
+
+        if (errs != null && !F.isEmpty(errs.getSuppressed()))
+            throw errs;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long ramBytesUsed() {
+        ensureOpen();
+
+        return sizeInBytes.get();
+    }
+
+    /** {@inheritDoc} */
+    @Override public synchronized Collection<Accountable> getChildResources() {
+        return Accountables.namedAccountables("file", new HashMap<>(fileMap));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneFile.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneFile.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneFile.java
index 3985f09..d7ae132 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneFile.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneFile.java
@@ -17,22 +17,19 @@
 
 package org.apache.ignite.internal.processors.query.h2.opt;
 
-import java.io.Serializable;
 import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.lucene.util.Accountable;
 
 import static org.apache.ignite.internal.processors.query.h2.opt.GridLuceneOutputStream.BUFFER_SIZE;
 
 /**
  * Lucene file.
  */
-public class GridLuceneFile implements Serializable {
-    /** */
-    private static final long serialVersionUID = 0L;
-
-    /** */
-    public static final AtomicInteger filesCnt = new AtomicInteger();
-
+public class GridLuceneFile implements Accountable {
     /** */
     private LongArray buffers = new LongArray();
 
@@ -45,6 +42,12 @@ public class GridLuceneFile implements Serializable {
     /** */
     private volatile long sizeInBytes;
 
+    /** */
+    private final AtomicLong refCnt = new AtomicLong();
+
+    /** */
+    private final AtomicBoolean deleted = new AtomicBoolean();
+
     /**
      * File used as buffer, in no RAMDirectory
      *
@@ -52,8 +55,6 @@ public class GridLuceneFile implements Serializable {
      */
     GridLuceneFile(GridLuceneDirectory dir) {
         this.dir = dir;
-
-        filesCnt.incrementAndGet();
     }
 
     /**
@@ -93,51 +94,89 @@ public class GridLuceneFile implements Serializable {
     }
 
     /**
+     * Increment ref counter.
+     */
+    void lockRef() {
+        refCnt.incrementAndGet();
+    }
+
+    /**
+     * Decrement ref counter.
+     */
+    void releaseRef() {
+        refCnt.decrementAndGet();
+
+        deferredDelete();
+    }
+
+    /**
+     * Checks if there is file stream opened.
+     *
+     * @return {@code True} if file has external references.
+     */
+    boolean hasRefs() {
+        long refs = refCnt.get();
+
+        assert refs >= 0;
+
+        return refs != 0;
+    }
+
+    /**
      * Gets address of buffer.
      *
      * @param idx Index.
      * @return Pointer.
      */
-    protected final synchronized long getBuffer(int idx) {
+    final synchronized long getBuffer(int idx) {
         return buffers.get(idx);
     }
 
     /**
      * @return Number of buffers.
      */
-    protected final synchronized int numBuffers() {
+    final synchronized int numBuffers() {
         return buffers.size();
     }
 
     /**
-     * Expert: allocate a new buffer.
-     * Subclasses can allocate differently.
+     * Expert: allocate a new buffer. Subclasses can allocate differently.
      *
      * @return allocated buffer.
      */
-    protected long newBuffer() {
+    private long newBuffer() {
         return dir.memory().allocate(BUFFER_SIZE);
     }
 
     /**
      * Deletes file and deallocates memory..
      */
-    public synchronized void delete() {
-        if (buffers == null)
+    public void delete() {
+        if (!deleted.compareAndSet(false, true))
             return;
 
+        deferredDelete();
+    }
+
+    /**
+     * Deferred delete.
+     */
+    synchronized void deferredDelete() {
+        if (!deleted.get() || hasRefs())
+            return;
+
+        assert refCnt.get() == 0;
+
         for (int i = 0; i < buffers.idx; i++)
             dir.memory().release(buffers.arr[i], BUFFER_SIZE);
 
         buffers = null;
-
-        filesCnt.decrementAndGet();
     }
 
     /**
      * @return Size in bytes.
      */
-    public long getSizeInBytes() {
+    long getSizeInBytes() {
         return sizeInBytes;
     }
 
@@ -148,6 +187,16 @@ public class GridLuceneFile implements Serializable {
         return dir;
     }
 
+    /** {@inheritDoc} */
+    @Override public long ramBytesUsed() {
+        return sizeInBytes;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<Accountable> getChildResources() {
+        return Collections.emptyList();
+    }
+
     /**
      * Simple expandable long[] wrapper.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneIndex.java
index eed5ee4..c51eb5d 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneIndex.java
@@ -296,7 +296,8 @@ public class GridLuceneIndex implements AutoCloseable {
     /** {@inheritDoc} */
     @Override public void close() {
         U.closeQuiet(writer);
-        U.closeQuiet(dir);
+
+        dir.close();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneInputStream.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneInputStream.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneInputStream.java
index 4820af1..9b1bf0c 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneInputStream.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneInputStream.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.query.h2.opt;
 import java.io.EOFException;
 import java.io.IOException;
 import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
+import org.apache.lucene.store.AlreadyClosedException;
 import org.apache.lucene.store.IndexInput;
 
 import static org.apache.ignite.internal.processors.query.h2.opt.GridLuceneOutputStream.BUFFER_SIZE;
@@ -27,7 +28,7 @@ import static org.apache.ignite.internal.processors.query.h2.opt.GridLuceneOutpu
 /**
  * A memory-resident {@link IndexInput} implementation.
  */
-public class GridLuceneInputStream extends IndexInput {
+public class GridLuceneInputStream extends IndexInput implements Cloneable {
     /** */
     private GridLuceneFile file;
 
@@ -52,6 +53,11 @@ public class GridLuceneInputStream extends IndexInput {
     /** */
     private final GridUnsafeMemory mem;
 
+    /** */
+    private volatile boolean closed;
+
+    /** */
+    private boolean isClone;
     /**
      * Constructor.
      *
@@ -91,7 +97,24 @@ public class GridLuceneInputStream extends IndexInput {
 
     /** {@inheritDoc} */
     @Override public void close() {
-        // nothing to do here
+        if (!isClone) {
+            closed = true;
+
+            file.releaseRef();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public IndexInput clone() {
+        GridLuceneInputStream clone = (GridLuceneInputStream) super.clone();
+
+        if(closed)
+            throw new AlreadyClosedException(toString());
+
+        clone.isClone = true;
+
+        return clone;
+
     }
 
     /** {@inheritDoc} */
@@ -222,14 +245,16 @@ public class GridLuceneInputStream extends IndexInput {
         public SlicedInputStream(String newResourceDescription, long offset, long length) throws IOException {
             super(newResourceDescription, GridLuceneInputStream.this.file, offset + length);
 
+            // Avoid parent resource closing together with this.
+            super.isClone = true;
+
             this.offset = offset;
 
             seek(0L);
         }
 
         /** {@inheritDoc} */
-        @Override
-        public void seek(long pos) throws IOException {
+        @Override public void seek(long pos) throws IOException {
             if (pos < 0L) {
                 throw new IllegalArgumentException("Seeking to negative position: " + this);
             }
@@ -237,20 +262,17 @@ public class GridLuceneInputStream extends IndexInput {
         }
 
         /** {@inheritDoc} */
-        @Override
-        public long getFilePointer() {
+        @Override public long getFilePointer() {
             return super.getFilePointer() - offset;
         }
 
         /** {@inheritDoc} */
-        @Override
-        public long length() {
+        @Override public long length() {
             return super.length() - offset;
         }
 
         /** {@inheritDoc} */
-        @Override
-        public IndexInput slice(String sliceDescription, long ofs, long len) throws IOException {
+        @Override public IndexInput slice(String sliceDescription, long ofs, long len) throws IOException {
             return super.slice(sliceDescription, offset + ofs, len);
         }
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneOutputStream.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneOutputStream.java
index caea226..d8f09df 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneOutputStream.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridLuceneOutputStream.java
@@ -18,17 +18,21 @@
 package org.apache.ignite.internal.processors.query.h2.opt;
 
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.zip.CRC32;
 import java.util.zip.Checksum;
 import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeMemory;
 import org.apache.lucene.store.BufferedChecksum;
 import org.apache.lucene.store.DataInput;
 import org.apache.lucene.store.IndexOutput;
+import org.apache.lucene.util.Accountable;
+import org.apache.lucene.util.Accountables;
 
 /**
  * A memory-resident {@link IndexOutput} implementation.
  */
-public class GridLuceneOutputStream extends IndexOutput {
+public class GridLuceneOutputStream extends IndexOutput implements Accountable {
     /** Off-heap page size. */
     static final int BUFFER_SIZE = 32 * 1024;
 
@@ -93,6 +97,8 @@ public class GridLuceneOutputStream extends IndexOutput {
     /** {@inheritDoc} */
     @Override public void close() throws IOException {
         flush();
+
+        file.releaseRef();
     }
 
     /** {@inheritDoc} */
@@ -201,4 +207,14 @@ public class GridLuceneOutputStream extends IndexOutput {
             bufPosition += toCp;
         }
     }
+
+    /** {@inheritDoc} */
+    @Override public long ramBytesUsed() {
+        return file.getSizeInBytes();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<Accountable> getChildResources() {
+        return Collections.singleton(Accountables.namedAccountable("file", file));
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
index ba0324f..ed092df 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
@@ -119,6 +119,10 @@ public class IgniteCacheFullTextQueryNodeJoiningSelfTest extends GridCommonAbstr
 
                 Ignite started = startGrid(GRID_CNT);
 
+                //TODO: remove next line when IGNITE-2229 issue will be fixed.
+                // see https://issues.apache.org/jira/browse/IGNITE-2229
+                awaitPartitionMapExchange();
+
                 for (int i = 0; i < 100; i++) {
                     QueryCursor<Cache.Entry<AffinityKey<Integer>, IndexedEntity>> res = started.cache(DEFAULT_CACHE_NAME)
                         .query(new TextQuery<AffinityKey<Integer>, IndexedEntity>(IndexedEntity.class, "indexed"));

http://git-wip-us.apache.org/repos/asf/ignite/blob/1e08c3fb/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
index 258eed8..1ad0d4b 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
@@ -47,6 +47,7 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheCollocatedQuerySel
 import org.apache.ignite.internal.processors.cache.IgniteCacheDeleteSqlQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheDuplicateEntityConfigurationSelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheFieldsQueryNoDataSelfTest;
+import org.apache.ignite.internal.processors.cache.IgniteCacheFullTextQueryNodeJoiningSelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheInsertSqlQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheJoinPartitionedAndReplicatedTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheJoinQueryWithAffinityKeyTest;
@@ -273,6 +274,7 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
 
         // Full text queries.
         suite.addTestSuite(GridCacheFullTextQuerySelfTest.class);
+        suite.addTestSuite(IgniteCacheFullTextQueryNodeJoiningSelfTest.class);
 
         // Ignite cache and H2 comparison.
         suite.addTestSuite(BaseH2CompareQueryTest.class);


[14/29] ignite git commit: IGNITE-5734 Web Console: Fixed npm dependencies. (cherry picked from commit aeafbf1)

Posted by nt...@apache.org.
IGNITE-5734 Web Console: Fixed npm dependencies.
(cherry picked from commit aeafbf1)


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

Branch: refs/heads/ignite-5947
Commit: 580b6aa8e5a8a887397eab5c4c830ec28f45cd30
Parents: ab18fdf
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Wed Aug 9 17:22:54 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Wed Aug 9 18:25:49 2017 +0700

----------------------------------------------------------------------
 modules/web-console/frontend/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/580b6aa8/modules/web-console/frontend/package.json
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/package.json b/modules/web-console/frontend/package.json
index 6b049ff..f96c322 100644
--- a/modules/web-console/frontend/package.json
+++ b/modules/web-console/frontend/package.json
@@ -57,7 +57,7 @@
     "babel-polyfill": "6.23.0",
     "babel-preset-es2015": "6.24.1",
     "babel-preset-stage-1": "6.24.1",
-    "babel-runtime": "6.23.0",
+    "babel-runtime": "6.25.0",
     "bootstrap-sass": "3.3.7",
     "brace": "0.10.0",
     "copy-webpack-plugin": "4.0.1",


[18/29] ignite git commit: IGNITE-6013 Optimized processing response from cluster. (cherry picked from commit b02c481)

Posted by nt...@apache.org.
IGNITE-6013 Optimized processing response from cluster.
(cherry picked from commit b02c481)


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

Branch: refs/heads/ignite-5947
Commit: 3a7d4f4a79e7c0a23244387e3a68535375a66a87
Parents: 8b24619
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Fri Aug 11 11:18:42 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Fri Aug 11 11:23:04 2017 +0700

----------------------------------------------------------------------
 .../console/agent/handlers/ClusterListener.java |  13 +-
 .../ignite/console/agent/rest/RestExecutor.java | 201 +++++++++++++++++--
 2 files changed, 194 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/3a7d4f4a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/ClusterListener.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/ClusterListener.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/ClusterListener.java
index b811a2d..435ce74 100644
--- a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/ClusterListener.java
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/ClusterListener.java
@@ -46,7 +46,7 @@ import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_BUILD_VER;
 import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_SUCCESS;
 
 /**
- * API to retranslate topology from Ignite cluster available by node-uri.
+ * API to transfer topology from Ignite cluster available by node-uri.
  */
 public class ClusterListener {
     /** */
@@ -65,7 +65,7 @@ public class ClusterListener {
     private static final long DFLT_TIMEOUT = 3000L;
 
     /** JSON object mapper. */
-    private static final ObjectMapper mapper = new GridJettyObjectMapper();
+    private static final ObjectMapper MAPPER = new GridJettyObjectMapper();
 
     /** Latest topology snapshot. */
     private TopologySnapshot top;
@@ -234,10 +234,7 @@ public class ClusterListener {
 
         /**  */
         boolean differentCluster(TopologySnapshot old) {
-            if (old == null || F.isEmpty(old.nids))
-                return true;
-
-            return Collections.disjoint(nids, old.nids);
+            return old == null || F.isEmpty(old.nids) || Collections.disjoint(nids, old.nids);
         }
     }
 
@@ -250,7 +247,7 @@ public class ClusterListener {
 
                 switch (res.getStatus()) {
                     case STATUS_SUCCESS:
-                        List<GridClientNodeBean> nodes = mapper.readValue(res.getData(),
+                        List<GridClientNodeBean> nodes = MAPPER.readValue(res.getData(),
                             new TypeReference<List<GridClientNodeBean>>() {});
 
                         TopologySnapshot newTop = new TopologySnapshot(nodes);
@@ -290,7 +287,7 @@ public class ClusterListener {
 
                 switch (res.getStatus()) {
                     case STATUS_SUCCESS:
-                        List<GridClientNodeBean> nodes = mapper.readValue(res.getData(),
+                        List<GridClientNodeBean> nodes = MAPPER.readValue(res.getData(),
                             new TypeReference<List<GridClientNodeBean>>() {});
 
                         TopologySnapshot newTop = new TopologySnapshot(nodes);

http://git-wip-us.apache.org/repos/asf/ignite/blob/3a7d4f4a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/rest/RestExecutor.java
----------------------------------------------------------------------
diff --git a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/rest/RestExecutor.java b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/rest/RestExecutor.java
index 03eca4e..13989b4 100644
--- a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/rest/RestExecutor.java
+++ b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/rest/RestExecutor.java
@@ -17,9 +17,16 @@
 
 package org.apache.ignite.console.agent.rest;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import java.io.IOException;
+import java.io.StringWriter;
 import java.net.ConnectException;
 import java.util.HashMap;
 import java.util.Map;
@@ -40,6 +47,9 @@ import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.logger.slf4j.Slf4jLogger;
 import org.slf4j.LoggerFactory;
 
+import static com.fasterxml.jackson.core.JsonToken.END_ARRAY;
+import static com.fasterxml.jackson.core.JsonToken.END_OBJECT;
+import static com.fasterxml.jackson.core.JsonToken.START_ARRAY;
 import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_AUTH_FAILED;
 import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_FAILED;
 import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_SUCCESS;
@@ -52,7 +62,7 @@ public class RestExecutor {
     private static final IgniteLogger log = new Slf4jLogger(LoggerFactory.getLogger(RestExecutor.class));
 
     /** JSON object mapper. */
-    private static final ObjectMapper mapper = new GridJettyObjectMapper();
+    private static final ObjectMapper MAPPER = new GridJettyObjectMapper();
 
     /** */
     private final OkHttpClient httpClient;
@@ -141,34 +151,35 @@ public class RestExecutor {
         reqBuilder.url(urlBuilder.build());
 
         try (Response resp = httpClient.newCall(reqBuilder.build()).execute()) {
-            String content = resp.body().string();
-
             if (resp.isSuccessful()) {
-                JsonNode node = mapper.readTree(content);
+                RestResponseHolder res = MAPPER.readValue(resp.body().byteStream(), RestResponseHolder.class);
 
-                int status = node.get("successStatus").asInt();
+                int status = res.getSuccessStatus();
 
                 switch (status) {
                     case STATUS_SUCCESS:
-                        return RestResult.success(node.get("response").toString());
+                        return RestResult.success(res.getResponse());
 
                     default:
-                        return RestResult.fail(status, node.get("error").asText());
+                        return RestResult.fail(status, res.getError());
                 }
             }
 
             if (resp.code() == 401)
-                return RestResult.fail(STATUS_AUTH_FAILED, "Failed to authenticate in grid. " +
+                return RestResult.fail(STATUS_AUTH_FAILED, "Failed to authenticate in cluster. " +
                     "Please check agent\'s login and password or node port.");
 
-            return RestResult.fail(STATUS_FAILED, "Failed connect to node and execute REST command.");
+            if (resp.code() == 404)
+                return RestResult.fail(STATUS_FAILED, "Failed connect to cluster.");
+
+            return RestResult.fail(STATUS_FAILED, "Failed to execute REST command: " + resp.message());
         }
         catch (ConnectException ignored) {
-            LT.warn(log, "Failed connect to node and execute REST command. " +
+            LT.warn(log, "Failed connect to cluster. " +
                 "Please ensure that nodes have [ignite-rest-http] module in classpath " +
                 "(was copied from libs/optional to libs folder).");
 
-            throw new ConnectException("Failed connect to node and execute REST command [url=" + urlBuilder + ", parameters=" + params + "]");
+            throw new ConnectException("Failed connect to cluster [url=" + urlBuilder + ", parameters=" + params + "]");
         }
     }
 
@@ -208,4 +219,170 @@ public class RestExecutor {
 
         return sendRequest(demo, "ignite", params, null, null);
     }
+
+    /**
+     * REST response holder Java bean.
+     */
+    private static class RestResponseHolder {
+        /** Success flag */
+        private int successStatus;
+
+        /** Error. */
+        private String err;
+
+        /** Response. */
+        private String res;
+
+        /** Session token string representation. */
+        private String sesTokStr;
+
+        /**
+         * @return {@code True} if this request was successful.
+         */
+        public int getSuccessStatus() {
+            return successStatus;
+        }
+
+        /**
+         * @param successStatus Whether request was successful.
+         */
+        public void setSuccessStatus(int successStatus) {
+            this.successStatus = successStatus;
+        }
+
+        /**
+         * @return Error.
+         */
+        public String getError() {
+            return err;
+        }
+
+        /**
+         * @param err Error.
+         */
+        public void setError(String err) {
+            this.err = err;
+        }
+
+        /**
+         * @return Response object.
+         */
+        public String getResponse() {
+            return res;
+        }
+
+        /**
+         * @param res Response object.
+         */
+        @JsonDeserialize(using = RawContentDeserializer.class)
+        public void setResponse(String res) {
+            this.res = res;
+        }
+
+        /**
+         * @return String representation of session token.
+         */
+        public String getSessionToken() {
+            return sesTokStr;
+        }
+
+        /**
+         * @param sesTokStr String representation of session token.
+         */
+        public void setSessionToken(String sesTokStr) {
+            this.sesTokStr = sesTokStr;
+        }
+    }
+
+    /**
+     * Raw content deserializer that will deserialize any data as string.
+     */
+    private static class RawContentDeserializer extends JsonDeserializer<String> {
+        /** */
+        private final JsonFactory factory = new JsonFactory();
+
+        /**
+         * @param tok Token to process.
+         * @param p Parser.
+         * @param gen Generator.
+         */
+        private void writeToken(JsonToken tok, JsonParser p, JsonGenerator gen) throws IOException {
+            switch (tok) {
+                case FIELD_NAME:
+                    gen.writeFieldName(p.getText());
+                    break;
+
+                case START_ARRAY:
+                    gen.writeStartArray();
+                    break;
+
+                case END_ARRAY:
+                    gen.writeEndArray();
+                    break;
+
+                case START_OBJECT:
+                    gen.writeStartObject();
+                    break;
+
+                case END_OBJECT:
+                    gen.writeEndObject();
+                    break;
+
+                case VALUE_NUMBER_INT:
+                    gen.writeNumber(p.getLongValue());
+                    break;
+
+                case VALUE_NUMBER_FLOAT:
+                    gen.writeNumber(p.getDoubleValue());
+                    break;
+
+                case VALUE_TRUE:
+                    gen.writeBoolean(true);
+                    break;
+
+                case VALUE_FALSE:
+                    gen.writeBoolean(false);
+                    break;
+
+                case VALUE_NULL:
+                    gen.writeNull();
+                    break;
+
+                default:
+                    gen.writeString(p.getText());
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+            JsonToken startTok = p.getCurrentToken();
+
+            if (startTok.isStructStart()) {
+                StringWriter wrt = new StringWriter(4096);
+
+                JsonGenerator gen = factory.createGenerator(wrt);
+
+                JsonToken tok = startTok, endTok = startTok == START_ARRAY ? END_ARRAY : END_OBJECT;
+
+                int cnt = 1;
+
+                while (cnt > 0) {
+                    writeToken(tok, p, gen);
+
+                    tok = p.nextToken();
+
+                    if (tok == startTok)
+                        cnt++;
+                    else if (tok == endTok)
+                        cnt--;
+                }
+
+                gen.close();
+
+                return wrt.toString();
+            }
+
+            return p.getValueAsString();
+        }
+    }
 }


[28/29] ignite git commit: IGNITE-6032: ODBC: Added SQL_SCROLL_OPTIONS support for SQLGetInfo

Posted by nt...@apache.org.
IGNITE-6032: ODBC: Added SQL_SCROLL_OPTIONS support for SQLGetInfo

(cherry picked from commit f3d3d1bd718068c941e14b4e5949573b0a5d0c6a)


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

Branch: refs/heads/ignite-5947
Commit: 020ff3608d07fc584effe0826d72eb5edac0e1d6
Parents: 276e84a
Author: Igor Sapego <is...@gridgain.com>
Authored: Tue Aug 15 16:55:31 2017 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Tue Aug 15 16:55:31 2017 +0300

----------------------------------------------------------------------
 .../cpp/odbc-test/src/meta_queries_test.cpp      | 13 +++++++++++++
 .../cpp/odbc/src/config/connection_info.cpp      | 19 ++++++++++++++++++-
 .../platforms/cpp/odbc/src/meta/column_meta.cpp  |  3 +++
 3 files changed, 34 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/020ff360/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
index ff3695d..5d4e22f 100644
--- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
@@ -337,4 +337,17 @@ BOOST_AUTO_TEST_CASE(TestGetDataWithSelectQuery)
     CheckSingleRowResultSetWithGetData(stmt);
 }
 
+BOOST_AUTO_TEST_CASE(TestGetInfoScrollOptions)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLUINTEGER val = 0;
+    SQLRETURN ret = SQLGetInfo(dbc, SQL_SCROLL_OPTIONS, &val, 0, 0);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
+
+    BOOST_CHECK_NE(val, 0);
+}
+
 BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/020ff360/modules/platforms/cpp/odbc/src/config/connection_info.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/config/connection_info.cpp b/modules/platforms/cpp/odbc/src/config/connection_info.cpp
index 4e7cc3c..4925957 100644
--- a/modules/platforms/cpp/odbc/src/config/connection_info.cpp
+++ b/modules/platforms/cpp/odbc/src/config/connection_info.cpp
@@ -118,6 +118,7 @@ namespace ignite
                     DBG_STR_CASE(SQL_CONVERT_WLONGVARCHAR);
                     DBG_STR_CASE(SQL_CONVERT_WVARCHAR);
                     DBG_STR_CASE(SQL_CONVERT_GUID);
+                    DBG_STR_CASE(SQL_SCROLL_OPTIONS);
                     DBG_STR_CASE(SQL_PARAM_ARRAY_ROW_COUNTS);
                     DBG_STR_CASE(SQL_PARAM_ARRAY_SELECTS);
                 default:
@@ -628,6 +629,19 @@ namespace ignite
                     SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_GUID;
 #endif //SQL_CONVERT_GUID
 
+#ifdef SQL_SCROLL_OPTIONS
+                // Bitmask enumerating the scroll options supported for scrollable cursors
+                // SQL_SO_FORWARD_ONLY = The cursor only scrolls forward. (ODBC 1.0)
+                // SQL_SO_STATIC = The data in the result set is static. (ODBC 2.0)
+                // SQL_SO_KEYSET_DRIVEN = The driver saves and uses the keys for every row in the result set. (ODBC 1.0)
+                // SQL_SO_DYNAMIC = The driver keeps the keys for every row in the rowset(the keyset size is the same
+                //     as the rowset size). (ODBC 1.0)
+                // SQL_SO_MIXED = The driver keeps the keys for every row in the keyset, and the keyset size is greater
+                //     than the rowset size.The cursor is keyset - driven inside the keyset and dynamic outside the
+                //     keyset. (ODBC 1.0)
+                intParams[SQL_SCROLL_OPTIONS] = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
+#endif //SQL_SCROLL_OPTIONS
+
                 //======================= Short Params ========================
 #ifdef SQL_MAX_CONCURRENT_ACTIVITIES
                 // The maximum number of active statements that the driver can
@@ -666,13 +680,16 @@ namespace ignite
             SqlResult::Type ConnectionInfo::GetInfo(InfoType type, void* buf,
                 short buflen, short* reslen) const
             {
-                if (!buf || !buflen)
+                if (!buf)
                     return SqlResult::AI_ERROR;
 
                 StringInfoMap::const_iterator itStr = strParams.find(type);
 
                 if (itStr != strParams.end())
                 {
+                    if (!buflen)
+                        return SqlResult::AI_ERROR;
+
                     unsigned short strlen = static_cast<short>(
                         utility::CopyStringToBuffer(itStr->second,
                             reinterpret_cast<char*>(buf), buflen));

http://git-wip-us.apache.org/repos/asf/ignite/blob/020ff360/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
index 97fdf80..f1bd9a1 100644
--- a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
+++ b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
@@ -60,6 +60,9 @@ namespace ignite
                     DBG_STR_CASE(SQL_DESC_UNNAMED);
                     DBG_STR_CASE(SQL_DESC_UNSIGNED);
                     DBG_STR_CASE(SQL_DESC_UPDATABLE);
+                    DBG_STR_CASE(SQL_COLUMN_LENGTH);
+                    DBG_STR_CASE(SQL_COLUMN_PRECISION);
+                    DBG_STR_CASE(SQL_COLUMN_SCALE);
                 default:
                     break;
                 }


[08/29] ignite git commit: IGNITE-5939: ODBC: SQLColAttributes now works with legacy attribute codes.

Posted by nt...@apache.org.
IGNITE-5939: ODBC: SQLColAttributes now works with legacy attribute codes.

(cherry picked from commit 70ffa2c)


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

Branch: refs/heads/ignite-5947
Commit: 4e0385fbc0f50548f2da3407fdfdfe939b463c67
Parents: 0b3a9a7
Author: Igor Sapego <is...@gridgain.com>
Authored: Fri Aug 4 18:34:27 2017 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Fri Aug 4 18:36:46 2017 +0300

----------------------------------------------------------------------
 .../cpp/odbc-test/src/meta_queries_test.cpp     | 51 ++++++++++++++++++++
 .../platforms/cpp/odbc/src/meta/column_meta.cpp |  3 ++
 2 files changed, 54 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/4e0385fb/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
index 5b7ae59..454a989 100644
--- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
@@ -186,4 +186,55 @@ BOOST_AUTO_TEST_CASE(TestGetTypeInfoAllTypes)
         BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
 }
 
+BOOST_AUTO_TEST_CASE(TestColAttributesColumnLength)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLCHAR req[] = "select strField from TestType";
+    SQLExecDirect(stmt, req, SQL_NTS);
+
+    SQLLEN intVal;
+    SQLCHAR strBuf[1024];
+    SQLSMALLINT strLen;
+
+    SQLRETURN ret = SQLColAttribute(stmt, 1, SQL_COLUMN_LENGTH, strBuf, sizeof(strBuf), &strLen, &intVal);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+}
+
+BOOST_AUTO_TEST_CASE(TestColAttributesColumnPresicion)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLCHAR req[] = "select strField from TestType";
+    SQLExecDirect(stmt, req, SQL_NTS);
+
+    SQLLEN intVal;
+    SQLCHAR strBuf[1024];
+    SQLSMALLINT strLen;
+
+    SQLRETURN ret = SQLColAttribute(stmt, 1, SQL_COLUMN_PRECISION, strBuf, sizeof(strBuf), &strLen, &intVal);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+}
+
+BOOST_AUTO_TEST_CASE(TestColAttributesColumnScale)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLCHAR req[] = "select strField from TestType";
+    SQLExecDirect(stmt, req, SQL_NTS);
+
+    SQLLEN intVal;
+    SQLCHAR strBuf[1024];
+    SQLSMALLINT strLen;
+
+    SQLRETURN ret = SQLColAttribute(stmt, 1, SQL_COLUMN_SCALE, strBuf, sizeof(strBuf), &strLen, &intVal);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+}
+
 BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/4e0385fb/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
index 12dbfc1..97fdf80 100644
--- a/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
+++ b/modules/platforms/cpp/odbc/src/meta/column_meta.cpp
@@ -179,6 +179,7 @@ namespace ignite
 
                     case SQL_DESC_LENGTH:
                     case SQL_DESC_OCTET_LENGTH:
+                    case SQL_COLUMN_LENGTH:
                     {
                         value = type_traits::BinaryTypeTransferLength(dataType);
 
@@ -200,6 +201,7 @@ namespace ignite
                     }
 
                     case SQL_DESC_PRECISION:
+                    case SQL_COLUMN_PRECISION:
                     {
                         value = type_traits::BinaryTypeColumnSize(dataType);
 
@@ -207,6 +209,7 @@ namespace ignite
                     }
 
                     case SQL_DESC_SCALE:
+                    case SQL_COLUMN_SCALE:
                     {
                         value = type_traits::BinaryTypeDecimalDigits(dataType);
 


[15/29] ignite git commit: IGNITE-5987 Added -nq (visor will not quit in batch mode) option for Visor Cmd. (cherry picked from commit 8d6e842)

Posted by nt...@apache.org.
IGNITE-5987 Added -nq (visor will not quit in batch mode) option for Visor Cmd.
(cherry picked from commit 8d6e842)


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

Branch: refs/heads/ignite-5947
Commit: 841db65e56063605475710bc170de4aea672c31d
Parents: 580b6aa
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Wed Aug 9 18:55:04 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Wed Aug 9 18:56:14 2017 +0700

----------------------------------------------------------------------
 .../org/apache/ignite/visor/commands/VisorConsole.scala | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/841db65e/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
index 19d130e..d53a0d5 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
@@ -92,6 +92,7 @@ class VisorConsole {
             println("        -cfg=<path>          - connect with specified configuration.")
             println("        -b=<path>            - batch mode with file.")
             println("        -e=cmd1;cmd2;...     - batch mode with commands.")
+            println("        -nq                  - batch mode will not quit after execution (useful for alerts monitoring).")
 
             visor.quit()
         }
@@ -103,6 +104,10 @@ class VisorConsole {
         val cfgFile = argValue("cfg", argLst)
         val batchFile = argValue("b", argLst)
         val batchCommand = argValue("e", argLst)
+        val noBatchQuit = hasArgName("nq", argLst)
+
+        if (noBatchQuit && batchFile.isEmpty && batchCommand.isEmpty)
+            visor.warn("Option \"-nq\" will be ignored because batch mode options \"-b\" or \"-e\" were not specified.")
 
         cfgFile.foreach(cfg => {
             if (cfg.trim.isEmpty) {
@@ -149,7 +154,10 @@ class VisorConsole {
             case Some(cmd) =>
                 visor.batchMode = true
 
-                new ByteArrayInputStream((cmd + "\nquit\n").getBytes("UTF-8"))
+                val script = if (noBatchQuit) cmd else cmd + "\nquit\n"
+
+                new ByteArrayInputStream(script.getBytes("UTF-8"))
+
             case None => new FileInputStream(FileDescriptor.in)
         }
 
@@ -159,7 +167,7 @@ class VisorConsole {
 
             new TerminalSupport(false) {}
         } catch {
-            case ignored: ClassNotFoundException => null
+            case _: ClassNotFoundException => null
         }
 
         val reader = new ConsoleReader(inputStream, System.out, term)


[12/29] ignite git commit: IGNITE-5993: Removed unused SQL-related classes and methods (old tree index, snapshots, etc). This closes #2414.

Posted by nt...@apache.org.
IGNITE-5993: Removed unused SQL-related classes and methods (old tree index, snapshots, etc). This closes #2414.


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

Branch: refs/heads/ignite-5947
Commit: 7c77b869bc3efdf19e53cc2b064f4290fd73e2b2
Parents: 879f191
Author: devozerov <vo...@gridgain.com>
Authored: Wed Aug 9 11:47:58 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Wed Aug 9 11:49:53 2017 +0300

----------------------------------------------------------------------
 .../query/h2/opt/GridH2SpatialIndex.java        |   7 -
 .../processors/query/h2/H2RowDescriptor.java    |  11 -
 .../processors/query/h2/H2TableEngine.java      |   4 +-
 .../query/h2/database/H2PkHashIndex.java        |   7 -
 .../query/h2/database/H2TreeIndex.java          |  26 -
 .../query/h2/opt/GridH2IndexBase.java           |  93 +--
 .../query/h2/opt/GridH2QueryContext.java        |  59 --
 .../query/h2/opt/GridH2RowDescriptor.java       |   5 -
 .../processors/query/h2/opt/GridH2Table.java    | 186 +-----
 .../query/h2/opt/GridH2TreeIndex.java           | 602 -------------------
 .../query/h2/twostep/GridMapQueryExecutor.java  |  25 -
 .../query/h2/opt/GridH2TableSelfTest.java       | 172 ------
 12 files changed, 7 insertions(+), 1190 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
----------------------------------------------------------------------
diff --git a/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java b/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
index 9389290..d83e860 100644
--- a/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
+++ b/modules/geospatial/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2SpatialIndex.java
@@ -31,7 +31,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.processors.query.h2.H2Cursor;
 import org.apache.ignite.internal.util.GridCursorIteratorWrapper;
-import org.apache.ignite.internal.util.IgniteTree;
 import org.apache.ignite.internal.util.lang.GridCursor;
 import org.h2.engine.Session;
 import org.h2.index.Cursor;
@@ -51,7 +50,6 @@ import org.h2.table.IndexColumn;
 import org.h2.table.TableFilter;
 import org.h2.value.Value;
 import org.h2.value.ValueGeometry;
-import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.KEY_COL;
 
@@ -158,11 +156,6 @@ public class GridH2SpatialIndex extends GridH2IndexBase implements SpatialIndex
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override protected IgniteTree doTakeSnapshot() {
-        return null; // TODO We do not support snapshots, but probably this is possible.
-    }
-
-    /** {@inheritDoc} */
     @Override public GridH2Row put(GridH2Row row) {
         assert row instanceof GridH2AbstractKeyValueRow : "requires key to be at 0";
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowDescriptor.java
index dab83d1..31f0e69 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2RowDescriptor.java
@@ -107,9 +107,6 @@ public class H2RowDescriptor implements GridH2RowDescriptor {
     private final GridUnsafeGuard guard;
 
     /** */
-    private final boolean snapshotableIdx;
-
-    /** */
     private final GridQueryProperty[] props;
 
     /** Id of user-defined key column */
@@ -170,9 +167,6 @@ public class H2RowDescriptor implements GridH2RowDescriptor {
 
         valueAliasColumnId =
             (type.valueFieldName() != null) ? DEFAULT_COLUMNS_COUNT + fieldsList.indexOf(type.valueFieldAlias()) : -1;
-
-        // Index is not snapshotable in db-x.
-        snapshotableIdx = false;
     }
 
     /** {@inheritDoc} */
@@ -382,11 +376,6 @@ public class H2RowDescriptor implements GridH2RowDescriptor {
     }
 
     /** {@inheritDoc} */
-    @Override public boolean snapshotableIndex() {
-        return snapshotableIdx;
-    }
-
-    /** {@inheritDoc} */
     @Override public boolean isKeyColumn(int columnId) {
         assert columnId >= 0;
         return columnId == KEY_COL || columnId == keyAliasColumnId;

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
index 57b7ba0..6bdcc30 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2TableEngine.java
@@ -56,8 +56,8 @@ public class H2TableEngine implements TableEngine {
      * @throws SQLException If failed.
      * @return Created table.
      */
-    public static synchronized GridH2Table createTable(Connection conn, String sql,
-        @Nullable GridH2RowDescriptor rowDesc, H2RowFactory rowFactory, H2TableDescriptor tblDesc)
+    public static synchronized GridH2Table createTable(Connection conn, String sql, GridH2RowDescriptor rowDesc,
+        H2RowFactory rowFactory, H2TableDescriptor tblDesc)
         throws SQLException {
         rowDesc0 = rowDesc;
         rowFactory0 = rowFactory;

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
index 2ae5868..1937a4b 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2PkHashIndex.java
@@ -30,7 +30,6 @@ import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
-import org.apache.ignite.internal.util.IgniteTree;
 import org.apache.ignite.internal.util.lang.GridCursor;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.spi.indexing.IndexingQueryFilter;
@@ -44,7 +43,6 @@ import org.h2.result.SortOrder;
 import org.h2.table.Column;
 import org.h2.table.IndexColumn;
 import org.h2.table.TableFilter;
-import org.jetbrains.annotations.Nullable;
 
 /**
  *
@@ -199,11 +197,6 @@ public class H2PkHashIndex extends GridH2IndexBase {
         throw new UnsupportedOperationException();
     }
 
-    /** {@inheritDoc} */
-    @Nullable @Override protected IgniteTree doTakeSnapshot() {
-        throw new AssertionError("This method must not be called for PK index");
-    }
-
     /**
      * Cursor.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
index e02510f..eb579c3 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/database/H2TreeIndex.java
@@ -215,25 +215,6 @@ public class H2TreeIndex extends GridH2IndexBase {
     }
 
     /** {@inheritDoc} */
-    @Override public boolean putx(GridH2Row row) {
-        try {
-            InlineIndexHelper.setCurrentInlineIndexes(inlineIdxs);
-
-            int seg = segmentForRow(row);
-
-            H2Tree tree = treeForRead(seg);
-
-            return tree.putx(row);
-        }
-        catch (IgniteCheckedException e) {
-            throw DbException.convert(e);
-        }
-        finally {
-            InlineIndexHelper.clearCurrentInlineIndexes();
-        }
-    }
-
-    /** {@inheritDoc} */
     @Override public GridH2Row remove(SearchRow row) {
         try {
             InlineIndexHelper.setCurrentInlineIndexes(inlineIdxs);
@@ -344,13 +325,6 @@ public class H2TreeIndex extends GridH2IndexBase {
     }
 
     /** {@inheritDoc} */
-    @Nullable @Override protected IgniteTree<SearchRow, GridH2Row> doTakeSnapshot() {
-        int seg = threadLocalSegment();
-
-        return treeForRead(seg);
-    }
-
-    /** {@inheritDoc} */
     @Override protected H2Tree treeForRead(int segment) {
         return segments[segment];
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
index 542adf0..5d5fb56 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2IndexBase.java
@@ -22,7 +22,6 @@ import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
 import javax.cache.CacheException;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteInterruptedException;
@@ -35,7 +34,6 @@ import org.apache.ignite.internal.managers.communication.GridIoPolicy;
 import org.apache.ignite.internal.managers.communication.GridMessageListener;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
-import org.apache.ignite.internal.processors.cache.distributed.dht.GridReservable;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2IndexRangeRequest;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2IndexRangeResponse;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2RowMessage;
@@ -93,15 +91,6 @@ public abstract class GridH2IndexBase extends BaseIndex {
     private static final Object EXPLICIT_NULL = new Object();
 
     /** */
-    private static final AtomicLong idxIdGen = new AtomicLong();
-
-    /** */
-    protected final long idxId = idxIdGen.incrementAndGet();
-
-    /** */
-    private final ThreadLocal<Object> snapshot = new ThreadLocal<>();
-
-    /** */
     private Object msgTopic;
 
     /** */
@@ -198,16 +187,6 @@ public abstract class GridH2IndexBase extends BaseIndex {
     public abstract GridH2Row put(GridH2Row row);
 
     /**
-     * Puts row.
-     *
-     * @param row Row.
-     * @return {@code True} if replaced existing row.
-     */
-    public boolean putx(GridH2Row row) {
-        return put(row) != null;
-    }
-
-    /**
      * Remove row from index.
      *
      * @param row Row.
@@ -233,32 +212,6 @@ public abstract class GridH2IndexBase extends BaseIndex {
     public abstract GridH2Row findOne(GridH2Row row);
 
     /**
-     * Takes or sets existing snapshot to be used in current thread.
-     *
-     * @param s Optional existing snapshot to use.
-     * @param qctx Query context.
-     * @return Snapshot.
-     */
-    public final Object takeSnapshot(@Nullable Object s, GridH2QueryContext qctx) {
-        assert snapshot.get() == null;
-
-        if (s == null)
-            s = doTakeSnapshot();
-
-        if (s != null) {
-            if (s instanceof GridReservable && !((GridReservable)s).reserve())
-                return null;
-
-            snapshot.set(s);
-
-            if (qctx != null)
-                qctx.putSnapshot(idxId, s);
-        }
-
-        return s;
-    }
-
-    /**
      * @param ses Session.
      */
     private static void clearViewIndexCache(Session ses) {
@@ -303,38 +256,6 @@ public abstract class GridH2IndexBase extends BaseIndex {
     }
 
     /**
-     * Takes and returns actual snapshot or {@code null} if snapshots are not supported.
-     *
-     * @return Snapshot or {@code null}.
-     */
-    @Nullable protected abstract IgniteTree doTakeSnapshot();
-
-    /**
-     * @return Thread local snapshot.
-     */
-    @SuppressWarnings("unchecked")
-    protected <T> T threadLocalSnapshot() {
-        return (T)snapshot.get();
-    }
-
-    /**
-     * Releases snapshot for current thread.
-     */
-    public void releaseSnapshot() {
-        Object s = snapshot.get();
-
-        assert s != null;
-
-        snapshot.remove();
-
-        if (s instanceof GridReservable)
-            ((GridReservable)s).release();
-
-        if (s instanceof AutoCloseable)
-            U.closeQuiet((AutoCloseable)s);
-    }
-
-    /**
      * Filters rows from expired ones and using predicate.
      *
      * @param cursor GridCursor over rows.
@@ -498,11 +419,9 @@ public abstract class GridH2IndexBase extends BaseIndex {
 
                 if (msg.bounds() != null) {
                     // This is the first request containing all the search rows.
-                    IgniteTree snapshotTree = qctx.getSnapshot(idxId);
-
                     assert !msg.bounds().isEmpty() : "empty bounds";
 
-                    src = new RangeSource(msg.bounds(), msg.segment(), snapshotTree, qctx.filter());
+                    src = new RangeSource(msg.bounds(), msg.segment(), qctx.filter());
                 }
                 else {
                     // This is request to fetch next portion of data.
@@ -619,7 +538,7 @@ public abstract class GridH2IndexBase extends BaseIndex {
 
         if (isLocalQry) {
             if (partMap != null && !partMap.containsKey(cctx.localNodeId()))
-                return Collections.<SegmentKey>emptyList(); // Prevent remote index call for local queries.
+                return Collections.emptyList(); // Prevent remote index call for local queries.
 
             nodes = Collections.singletonList(cctx.localNode());
         }
@@ -1543,9 +1462,6 @@ public abstract class GridH2IndexBase extends BaseIndex {
         int curRangeId = -1;
 
         /** */
-        final IgniteTree tree;
-
-        /** */
         private final int segment;
 
         /** */
@@ -1556,18 +1472,15 @@ public abstract class GridH2IndexBase extends BaseIndex {
 
         /**
          * @param bounds Bounds.
-         * @param tree Snapshot.
          * @param filter Filter.
          */
         RangeSource(
             Iterable<GridH2RowRangeBounds> bounds,
             int segment,
-            IgniteTree tree,
             IndexingQueryFilter filter
         ) {
             this.segment = segment;
             this.filter = filter;
-            this.tree = tree;
             boundsIter = bounds.iterator();
         }
 
@@ -1623,7 +1536,7 @@ public abstract class GridH2IndexBase extends BaseIndex {
                 SearchRow first = toSearchRow(bounds.first());
                 SearchRow last = toSearchRow(bounds.last());
 
-                IgniteTree t = tree != null ? tree : treeForRead(segment);
+                IgniteTree t = treeForRead(segment);
 
                 iter = new CursorIteratorWrapper(doFind0(t, first, true, last, filter));
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2QueryContext.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2QueryContext.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2QueryContext.java
index a7ee0dc..2b4e180 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2QueryContext.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2QueryContext.java
@@ -25,7 +25,6 @@ import java.util.concurrent.ConcurrentMap;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridReservable;
-import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.spi.indexing.IndexingQueryFilter;
@@ -51,10 +50,6 @@ public class GridH2QueryContext {
     /** */
     private volatile boolean cleared;
 
-    /** Index snapshots. */
-    @GridToStringInclude
-    private Map<Long, Object> snapshots;
-
     /** */
     private List<GridReservable> reservations;
 
@@ -248,51 +243,6 @@ public class GridH2QueryContext {
     }
 
     /**
-     * @param idxId Index ID.
-     * @param snapshot Index snapshot.
-     */
-    public void putSnapshot(long idxId, Object snapshot) {
-        assert snapshot != null;
-        assert get() == null : "need to snapshot indexes before setting query context for correct visibility";
-
-        if (snapshot instanceof GridReservable && !((GridReservable)snapshot).reserve())
-            throw new IllegalStateException("Must be already reserved before.");
-
-        if (snapshots == null)
-            snapshots = new HashMap<>();
-
-        if (snapshots.put(idxId, snapshot) != null)
-            throw new IllegalStateException("Index already snapshoted.");
-    }
-
-    /**
-     * Clear taken snapshots.
-     */
-    public void clearSnapshots() {
-        if (F.isEmpty(snapshots))
-            return;
-
-        for (Object snapshot : snapshots.values()) {
-            if (snapshot instanceof GridReservable)
-                ((GridReservable)snapshot).release();
-        }
-
-        snapshots = null;
-    }
-
-    /**
-     * @param idxId Index ID.
-     * @return Index snapshot or {@code null} if none.
-     */
-    @SuppressWarnings("unchecked")
-    public <T> T getSnapshot(long idxId) {
-        if (snapshots == null)
-            return null;
-
-        return (T)snapshots.get(idxId);
-    }
-
-    /**
      * @param batchLookupId Batch lookup ID.
      * @param streams Range streams.
      */
@@ -363,13 +313,6 @@ public class GridH2QueryContext {
     }
 
     /**
-     * @return If indexes were snapshotted before query execution.
-     */
-    public boolean hasIndexSnapshots() {
-        return snapshots != null;
-    }
-
-    /**
      * Sets current thread local context. This method must be called when all the non-volatile properties are
      * already set to ensure visibility for other threads.
      *
@@ -440,8 +383,6 @@ public class GridH2QueryContext {
     public void clearContext(boolean nodeStop) {
         cleared = true;
 
-        clearSnapshots();
-
         List<GridReservable> r = reservations;
 
         if (!nodeStop && !F.isEmpty(r)) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
index ce73010..d273e16 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2RowDescriptor.java
@@ -154,11 +154,6 @@ public interface GridH2RowDescriptor extends GridOffHeapSmartPointerFactory<Grid
     public Value wrap(Object o, int type) throws IgniteCheckedException;
 
     /**
-     * @return {@code True} if index should support snapshots.
-     */
-    public boolean snapshotableIndex();
-
-    /**
      * Checks if provided column id matches key column or key alias.
      *
      * @param colId Column id.

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
index 76d0258..f76cb5f 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2Table.java
@@ -22,8 +22,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReferenceArray;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -61,7 +59,6 @@ import org.jsr166.LongAdder8;
 
 import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2AbstractKeyValueRow.KEY_COL;
-import static org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryType.MAP;
 
 /**
  * H2 Table implementation.
@@ -95,18 +92,12 @@ public class GridH2Table extends TableBase {
     private final ConcurrentMap<Session, Boolean> sessions = new ConcurrentHashMap8<>();
 
     /** */
-    private final AtomicReferenceArray<Object[]> actualSnapshot;
-
-    /** */
     private IndexColumn affKeyCol;
 
     /** */
     private final LongAdder8 size = new LongAdder8();
 
     /** */
-    private final boolean snapshotEnabled;
-
-    /** */
     private final H2RowFactory rowFactory;
 
     /** */
@@ -127,7 +118,7 @@ public class GridH2Table extends TableBase {
      * @param idxsFactory Indexes factory.
      * @param cctx Cache context.
      */
-    public GridH2Table(CreateTableData createTblData, @Nullable GridH2RowDescriptor desc, H2RowFactory rowFactory,
+    public GridH2Table(CreateTableData createTblData, GridH2RowDescriptor desc, H2RowFactory rowFactory,
         GridH2SystemIndexFactory idxsFactory, GridCacheContext cctx) {
         super(createTblData);
 
@@ -136,7 +127,7 @@ public class GridH2Table extends TableBase {
         this.desc = desc;
         this.cctx = cctx;
 
-        if (desc != null && desc.context() != null && !desc.context().customAffinityMapper()) {
+        if (desc.context() != null && !desc.context().customAffinityMapper()) {
             boolean affinityColExists = true;
 
             String affKey = desc.type().affinityKey();
@@ -186,18 +177,10 @@ public class GridH2Table extends TableBase {
         else
             idxs.add(0, new GridH2PrimaryScanIndex(this, index(0), null));
 
-        snapshotEnabled = desc == null || desc.snapshotableIndex();
-
         pkIndexPos = hasHashIndex ? 2 : 1;
 
         sysIdxsCnt = idxs.size();
 
-        final int segments = desc != null ? desc.context().config().getQueryParallelism() :
-            // Get index segments count from PK index. Null desc can be passed from tests.
-            index(pkIndexPos).segmentsCount();
-
-        actualSnapshot = snapshotEnabled ? new AtomicReferenceArray<Object[]>(Math.max(segments, 1)) : null;
-
         lock = new ReentrantReadWriteLock();
     }
 
@@ -259,79 +242,10 @@ public class GridH2Table extends TableBase {
             throw new IllegalStateException("Table " + identifierString() + " already destroyed.");
         }
 
-        if (snapshotInLock()) {
-            final GridH2QueryContext qctx = GridH2QueryContext.get();
-
-            assert qctx != null;
-
-            snapshotIndexes(null, qctx.segment());
-        }
-
         return false;
     }
 
     /**
-     * @return {@code True} If we must snapshot and release index snapshots in {@link #lock(Session, boolean, boolean)}
-     * and {@link #unlock(Session)} methods.
-     */
-    private boolean snapshotInLock() {
-        if (!snapshotEnabled)
-            return false;
-
-        GridH2QueryContext qctx = GridH2QueryContext.get();
-
-        // On MAP queries with distributed joins we lock tables before the queries.
-        return qctx == null || qctx.type() != MAP || !qctx.hasIndexSnapshots();
-    }
-
-    /**
-     * @param qctx Query context.
-     * @param segment id of index segment to be snapshoted.
-     */
-    public void snapshotIndexes(GridH2QueryContext qctx, int segment) {
-        if (!snapshotEnabled)
-            return;
-
-        Object[] segmentSnapshot;
-
-        // Try to reuse existing snapshots outside of the lock.
-        for (long waitTime = 200; ; waitTime *= 2) { // Increase wait time to avoid starvation.
-            segmentSnapshot = actualSnapshot.get(segment);
-
-            if (segmentSnapshot != null) { // Reuse existing snapshot without locking.
-                segmentSnapshot = doSnapshotIndexes(segment, segmentSnapshot, qctx);
-
-                if (segmentSnapshot != null)
-                    return; // Reused successfully.
-            }
-
-            if (tryLock(true, waitTime))
-                break;
-        }
-
-        try {
-            ensureNotDestroyed();
-
-            // Try again inside of the lock.
-            segmentSnapshot = actualSnapshot.get(segment);
-
-            if (segmentSnapshot != null) // Try reusing.
-                segmentSnapshot = doSnapshotIndexes(segment, segmentSnapshot, qctx);
-
-            if (segmentSnapshot == null) { // Reuse failed, produce new snapshots.
-                segmentSnapshot = doSnapshotIndexes(segment,null, qctx);
-
-                assert segmentSnapshot != null;
-
-                actualSnapshot.set(segment, segmentSnapshot);
-            }
-        }
-        finally {
-            unlock(true);
-        }
-    }
-
-    /**
      * @return Table identifier.
      */
     public QueryTable identifier() {
@@ -364,27 +278,6 @@ public class GridH2Table extends TableBase {
     }
 
     /**
-     * @param exclusive Exclusive lock.
-     * @param waitMillis Milliseconds to wait for the lock.
-     * @return Whether lock was acquired.
-     */
-    private boolean tryLock(boolean exclusive, long waitMillis) {
-        Lock l = exclusive ? lock.writeLock() : lock.readLock();
-
-        try {
-            if (!l.tryLock(waitMillis, TimeUnit.MILLISECONDS))
-                return false;
-        }
-        catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-
-            throw new IgniteInterruptedException("Thread got interrupted while trying to acquire table lock.", e);
-        }
-
-        return true;
-    }
-
-    /**
      * Release table lock.
      *
      * @param exclusive Exclusive flag.
@@ -403,55 +296,6 @@ public class GridH2Table extends TableBase {
             throw new IllegalStateException("Table " + identifierString() + " already destroyed.");
     }
 
-    /**
-     * Must be called inside of write lock because when using multiple indexes we have to ensure that all of them have
-     * the same contents at snapshot taking time.
-     *
-     * @param segment id of index segment snapshot.
-     * @param segmentSnapshot snapshot to be reused.
-     * @param qctx Query context.
-     * @return New indexes data snapshot.
-     */
-    @SuppressWarnings("unchecked")
-    private Object[] doSnapshotIndexes(int segment, Object[] segmentSnapshot, GridH2QueryContext qctx) {
-        assert snapshotEnabled;
-
-        //TODO: make HashIndex snapshotable or remove it at all?
-        if (segmentSnapshot == null) // Nothing to reuse, create new snapshots.
-            segmentSnapshot = new Object[idxs.size() - pkIndexPos];
-
-        // Take snapshots on all except first which is scan.
-        for (int i = pkIndexPos, len = idxs.size(); i < len; i++) {
-            Object s = segmentSnapshot[i - pkIndexPos];
-
-            boolean reuseExisting = s != null;
-
-            if (!(idxs.get(i) instanceof GridH2IndexBase))
-                continue;
-
-            s = index(i).takeSnapshot(s, qctx);
-
-            if (reuseExisting && s == null) { // Existing snapshot was invalidated before we were able to reserve it.
-                // Release already taken snapshots.
-                if (qctx != null)
-                    qctx.clearSnapshots();
-
-                for (int j = pkIndexPos; j < i; j++)
-                    if ((idxs.get(j) instanceof GridH2IndexBase))
-                        index(j).releaseSnapshot();
-
-                // Drop invalidated snapshot.
-                actualSnapshot.compareAndSet(segment, segmentSnapshot, null);
-
-                return null;
-            }
-
-            segmentSnapshot[i - pkIndexPos] = s;
-        }
-
-        return segmentSnapshot;
-    }
-
     /** {@inheritDoc} */
     @Override public void close(Session ses) {
         // No-op.
@@ -525,32 +369,10 @@ public class GridH2Table extends TableBase {
         if (exclusive == null)
             return;
 
-        if (snapshotInLock())
-            releaseSnapshots();
-
         unlock(exclusive);
     }
 
     /**
-     * Releases snapshots.
-     */
-    public void releaseSnapshots() {
-        if (!snapshotEnabled)
-            return;
-
-        releaseSnapshots0(idxs);
-    }
-
-    /**
-     * @param idxs Indexes.
-     */
-    private void releaseSnapshots0(ArrayList<Index> idxs) {
-        // Release snapshots on all except first which is scan and second which is hash.
-        for (int i = 2, len = idxs.size(); i < len; i++)
-            ((GridH2IndexBase)idxs.get(i)).releaseSnapshot();
-    }
-
-    /**
      * Updates table for given key. If value is null then row with given key will be removed from table,
      * otherwise value and expiration time will be updated or new row will be added.
      *
@@ -700,10 +522,6 @@ public class GridH2Table extends TableBase {
                     return false;
             }
 
-            // The snapshot is not actual after update.
-            if (actualSnapshot != null)
-                actualSnapshot.set(pk.segmentForRow(row), null);
-
             return true;
         }
         finally {

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java
deleted file mode 100644
index 03fedcb..0000000
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TreeIndex.java
+++ /dev/null
@@ -1,602 +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.query.h2.opt;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.concurrent.ConcurrentSkipListMap;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.processors.query.h2.H2Cursor;
-import org.apache.ignite.internal.util.GridCursorIteratorWrapper;
-import org.apache.ignite.internal.util.IgniteTree;
-import org.apache.ignite.internal.util.lang.GridCursor;
-import org.apache.ignite.internal.util.offheap.unsafe.GridOffHeapSnapTreeMap;
-import org.apache.ignite.internal.util.offheap.unsafe.GridUnsafeGuard;
-import org.apache.ignite.internal.util.snaptree.SnapTreeMap;
-import org.apache.ignite.internal.util.typedef.internal.SB;
-import org.apache.ignite.spi.indexing.IndexingQueryFilter;
-import org.h2.engine.Session;
-import org.h2.index.Cursor;
-import org.h2.index.IndexType;
-import org.h2.index.SingleRowCursor;
-import org.h2.message.DbException;
-import org.h2.result.SearchRow;
-import org.h2.result.SortOrder;
-import org.h2.table.Column;
-import org.h2.table.IndexColumn;
-import org.h2.table.TableFilter;
-import org.h2.value.Value;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Base class for snapshotable segmented tree indexes.
- */
-@SuppressWarnings("ComparatorNotSerializable")
-public class GridH2TreeIndex extends GridH2IndexBase implements Comparator<GridSearchRowPointer> {
-    /** */
-    private final IgniteNavigableMapTree[] segments;
-
-    /** */
-    private final boolean snapshotEnabled;
-
-    /**
-     * Constructor with index initialization. Creates index with single segment.
-     *
-     * @param name Index name.
-     * @param tbl Table.
-     * @param pk If this index is primary key.
-     * @param colsList Index columns list.
-     */
-    @SuppressWarnings("unchecked")
-    public GridH2TreeIndex(String name, GridH2Table tbl, boolean pk, List<IndexColumn> colsList) {
-        this(name, tbl, pk, colsList, 1);
-    }
-
-    /**
-     * Constructor with index initialization.
-     *
-     * @param name Index name.
-     * @param tbl Table.
-     * @param pk If this index is primary key.
-     * @param colsList Index columns list.
-     * @param segmentsCnt Number of segments.
-     */
-    @SuppressWarnings("unchecked")
-    public GridH2TreeIndex(String name, GridH2Table tbl, boolean pk, List<IndexColumn> colsList, int segmentsCnt) {
-        assert segmentsCnt > 0 : segmentsCnt;
-
-        IndexColumn[] cols = colsList.toArray(new IndexColumn[colsList.size()]);
-
-        IndexColumn.mapColumns(cols, tbl);
-
-        initBaseIndex(tbl, 0, name, cols,
-            pk ? IndexType.createPrimaryKey(false, false) : IndexType.createNonUnique(false, false, false));
-
-        segments = new IgniteNavigableMapTree[segmentsCnt];
-
-        final GridH2RowDescriptor desc = tbl.rowDescriptor();
-
-        if (desc == null || desc.memory() == null) {
-            snapshotEnabled = desc == null || desc.snapshotableIndex();
-
-            if (snapshotEnabled) {
-                for (int i = 0; i < segmentsCnt; i++) {
-                    segments[i] = new IgniteNavigableMapTree(new SnapTreeMap<GridSearchRowPointer, GridH2Row>(this) {
-                        @Override protected void afterNodeUpdate_nl(Node<GridSearchRowPointer, GridH2Row> node, Object val) {
-                            if (val != null)
-                                node.key = (GridSearchRowPointer)val;
-                        }
-
-                        @Override protected Comparable<? super GridSearchRowPointer> comparable(Object key) {
-                            if (key instanceof ComparableRow)
-                                return (Comparable<? super SearchRow>)key;
-
-                            return super.comparable(key);
-                        }
-                    });
-                }
-            }
-            else {
-                for (int i = 0; i < segmentsCnt; i++) {
-                    segments[i] = new IgniteNavigableMapTree(
-                    new ConcurrentSkipListMap<GridSearchRowPointer, GridH2Row>(
-                        new Comparator<GridSearchRowPointer>() {
-                            @Override public int compare(GridSearchRowPointer o1, GridSearchRowPointer o2) {
-                                if (o1 instanceof ComparableRow)
-                                    return ((ComparableRow)o1).compareTo(o2);
-
-                                if (o2 instanceof ComparableRow)
-                                    return -((ComparableRow)o2).compareTo(o1);
-
-                                return compareRows(o1, o2);
-                            }
-                        }
-                    ));
-                }
-            }
-        }
-        else {
-            assert desc.snapshotableIndex() : desc;
-
-            snapshotEnabled = true;
-
-            for (int i = 0; i < segmentsCnt; i++) {
-                segments[i] = new IgniteNavigableMapTree(new GridOffHeapSnapTreeMap<GridSearchRowPointer, GridH2Row>(desc, desc, desc.memory(), desc.guard(), this) {
-                    @Override protected void afterNodeUpdate_nl(long node, GridH2Row val) {
-                        final long oldKey = keyPtr(node);
-
-                        if (val != null) {
-                            key(node, val);
-
-                            guard.finalizeLater(new Runnable() {
-                                @Override public void run() {
-                                    desc.createPointer(oldKey).decrementRefCount();
-                                }
-                            });
-                        }
-                    }
-
-                    @Override protected Comparable<? super GridSearchRowPointer> comparable(Object key) {
-                        if (key instanceof ComparableRow)
-                            return (Comparable<? super SearchRow>)key;
-
-                        return super.comparable(key);
-                    }
-                });
-            }
-        }
-
-        initDistributedJoinMessaging(tbl);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected IgniteTree doTakeSnapshot() {
-        assert snapshotEnabled;
-
-        int seg = threadLocalSegment();
-
-        IgniteNavigableMapTree tree = segments[seg];
-
-        return tree.clone();
-    }
-
-    /** {@inheritDoc} */
-    @Override protected final IgniteTree treeForRead(int seg) {
-        if (!snapshotEnabled)
-            return segments[seg];
-
-        IgniteTree res = threadLocalSnapshot();
-
-        if (res == null)
-            return segments[seg];
-
-        return res;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void destroy() {
-        assert threadLocalSnapshot() == null;
-
-        super.destroy();
-    }
-
-    /** {@inheritDoc} */
-    @Override public long getRowCount(@Nullable Session ses) {
-        IndexingQueryFilter f = threadLocalFilter();
-
-        int seg = threadLocalSegment();
-
-        // Fast path if we don't need to perform any filtering.
-        if (f == null || f.forCache((getTable()).cacheName()) == null)
-            try {
-                return treeForRead(seg).size();
-            } catch (IgniteCheckedException e) {
-                throw DbException.convert(e);
-            }
-
-        GridCursor<GridH2Row> cursor = doFind(null, false, null);
-
-        long size = 0;
-
-        try {
-            while (cursor.next())
-                size++;
-        }
-        catch (IgniteCheckedException e) {
-            throw DbException.convert(e);
-        }
-
-        return size;
-    }
-
-    /** {@inheritDoc} */
-    @Override public long getRowCountApproximation() {
-        return table.getRowCountApproximation();
-    }
-
-    /** {@inheritDoc} */
-    @Override public int compare(GridSearchRowPointer r1, GridSearchRowPointer r2) {
-        // Second row here must be data row if first is a search row.
-        return -compareRows(r2, r1);
-    }
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        SB sb = new SB((indexType.isUnique() ? "Unique index '" : "Index '") + getName() + "' [");
-
-        boolean first = true;
-
-        for (IndexColumn col : getIndexColumns()) {
-            if (first)
-                first = false;
-            else
-                sb.a(", ");
-
-            sb.a(col.getSQL());
-        }
-
-        sb.a(" ]");
-
-        return sb.toString();
-    }
-
-    /** {@inheritDoc} */
-    @Override public double getCost(Session ses, int[] masks, TableFilter[] filters, int filter,
-        SortOrder sortOrder, HashSet<Column> cols) {
-        long rowCnt = getRowCountApproximation();
-        double baseCost = getCostRangeIndex(masks, rowCnt, filters, filter, sortOrder, false, cols);
-        int mul = getDistributedMultiplier(ses, filters, filter);
-
-        return mul * baseCost;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean canFindNext() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Cursor find(Session ses, @Nullable SearchRow first, @Nullable SearchRow last) {
-        return new H2Cursor(doFind(first, true, last), null);
-    }
-
-    /** {@inheritDoc} */
-    @Override public Cursor findNext(Session ses, SearchRow higherThan, SearchRow last) {
-        return new H2Cursor(doFind(higherThan, false, last), null);
-    }
-
-    /**
-     * Finds row with key equal one in given search row.
-     * WARNING!! Method call must be protected by {@link GridUnsafeGuard#begin()}
-     * {@link GridUnsafeGuard#end()} block.
-     *
-     * @param row Search row.
-     * @return Row.
-     */
-    @Override public GridH2Row findOne(GridH2Row row) {
-        int seg = segmentForRow(row);
-
-        return segments[seg].findOne(row);
-    }
-
-    /**
-     * Returns sub-tree bounded by given values.
-     *
-     * @param first Lower bound.
-     * @param includeFirst Whether lower bound should be inclusive.
-     * @param last Upper bound always inclusive.
-     * @return Iterator over rows in given range.
-     */
-    @SuppressWarnings("unchecked")
-    private GridCursor<GridH2Row> doFind(@Nullable SearchRow first, boolean includeFirst, @Nullable SearchRow last) {
-        int seg = threadLocalSegment();
-
-        IgniteTree t = treeForRead(seg);
-
-        return doFind0(t, first, includeFirst, last, threadLocalFilter());
-    }
-
-    /** {@inheritDoc} */
-    @Override protected final GridCursor<GridH2Row> doFind0(
-        IgniteTree t,
-        @Nullable SearchRow first,
-        boolean includeFirst,
-        @Nullable SearchRow last,
-        IndexingQueryFilter filter
-    ) {
-        includeFirst &= first != null;
-
-        GridCursor<GridH2Row> range = subTree(t, comparable(first, includeFirst ? -1 : 1),
-            comparable(last, 1));
-
-        if (range == null)
-            return EMPTY_CURSOR;
-
-        return filter(range, filter);
-    }
-
-    /**
-     * @param row Row.
-     * @param bias Bias.
-     * @return Comparable row.
-     */
-    private GridSearchRowPointer comparable(SearchRow row, int bias) {
-        if (row == null)
-            return null;
-
-        if (bias == 0 && row instanceof GridH2Row)
-            return (GridSearchRowPointer)row;
-
-        return new ComparableRow(row, bias);
-    }
-
-    /**
-     * Takes sup-map from given one.
-     *
-     * @param tree Tree.
-     * @param first Lower bound.
-     * @param last Upper bound.
-     * @return Sub-map.
-     */
-    @SuppressWarnings({"IfMayBeConditional", "TypeMayBeWeakened"})
-    private GridCursor<GridH2Row> subTree(IgniteTree tree,
-        @Nullable GridSearchRowPointer first, @Nullable GridSearchRowPointer last) {
-
-        if (first != null && last != null && compare(first, last) > 0)
-            return null;
-
-        try {
-            // We take exclusive bounds because it is possible that one search row will be equal to multiple key rows
-            // in tree and we must return them all.
-            return tree.find(first, last);
-        }
-        catch (IgniteCheckedException e) {
-            throw DbException.convert(e);
-        }
-    }
-
-    /**
-     * Gets iterator over all rows in this index.
-     *
-     * @return Rows iterator.
-     */
-    GridCursor<GridH2Row> rows() {
-        return doFind(null, false, null);
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean canGetFirstOrLast() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Cursor findFirstOrLast(Session ses, boolean first) {
-        try {
-            int seg = threadLocalSegment();
-
-            IgniteTree t = treeForRead(seg);
-
-            GridH2Row row = (GridH2Row)(first ? t.findFirst() : t.findLast());
-
-            return new SingleRowCursor(row);
-        }
-        catch (IgniteCheckedException e) {
-            throw DbException.convert(e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override public GridH2Row put(GridH2Row row) {
-        int seg = segmentForRow(row);
-
-        return segments[seg].put(row);
-    }
-
-    /** {@inheritDoc} */
-    @Override public GridH2Row remove(SearchRow row) {
-        GridSearchRowPointer comparable = comparable(row, 0);
-
-        int seg = segmentForRow(row);
-
-        return segments[seg].remove(comparable);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected int segmentsCount() {
-        return segments.length;
-    }
-
-    /**
-     * Comparable row with bias. Will be used for queries to have correct bounds (in case of multicolumn index
-     * and query on few first columns we will multiple equal entries in tree).
-     */
-    private final class ComparableRow implements GridSearchRowPointer, Comparable<SearchRow> {
-        /** */
-        private final SearchRow row;
-
-        /** */
-        private final int bias;
-
-        /**
-         * @param row Row.
-         * @param bias Bias.
-         */
-        private ComparableRow(SearchRow row, int bias) {
-            this.row = row;
-            this.bias = bias;
-        }
-
-        /** {@inheritDoc} */
-        @Override public int compareTo(SearchRow o) {
-            int res = compareRows(o, row);
-
-            if (res == 0)
-                return bias;
-
-            return -res;
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean equals(Object obj) {
-            throw new IllegalStateException("Should never be called.");
-        }
-
-        /** {@inheritDoc} */
-        @Override public int getColumnCount() {
-            return row.getColumnCount();
-        }
-
-        /** {@inheritDoc} */
-        @Override public Value getValue(int idx) {
-            return row.getValue(idx);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setValue(int idx, Value v) {
-            row.setValue(idx, v);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setKeyAndVersion(SearchRow old) {
-            row.setKeyAndVersion(old);
-        }
-
-        /** {@inheritDoc} */
-        @Override public int getVersion() {
-            return row.getVersion();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setKey(long key) {
-            row.setKey(key);
-        }
-
-        /** {@inheritDoc} */
-        @Override public long getKey() {
-            return row.getKey();
-        }
-
-        /** {@inheritDoc} */
-        @Override public int getMemory() {
-            return row.getMemory();
-        }
-
-        /** {@inheritDoc} */
-        @Override public long pointer() {
-            throw new IllegalStateException();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void incrementRefCount() {
-            throw new IllegalStateException();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void decrementRefCount() {
-            throw new IllegalStateException();
-        }
-    }
-
-    /**
-     * Adapter from {@link NavigableMap} to {@link IgniteTree}.
-     */
-    private static final class IgniteNavigableMapTree implements IgniteTree<GridSearchRowPointer, GridH2Row>, Cloneable {
-        /** Tree. */
-        private final NavigableMap<GridSearchRowPointer, GridH2Row> tree;
-
-        /**
-         * @param tree Tree.
-         */
-        private IgniteNavigableMapTree(NavigableMap<GridSearchRowPointer, GridH2Row> tree) {
-            this.tree = tree;
-        }
-
-        /** {@inheritDoc} */
-        @Override public void invoke(GridSearchRowPointer key, Object x, InvokeClosure<GridH2Row> c) {
-            throw new UnsupportedOperationException();
-        }
-
-        /** {@inheritDoc} */
-        @Override public GridH2Row put(GridH2Row val) {
-            return tree.put(val, val);
-        }
-
-        /** {@inheritDoc} */
-        @Override public GridH2Row findOne(GridSearchRowPointer key) {
-            return tree.get(key);
-        }
-
-        /** {@inheritDoc} */
-        @Override public GridCursor<GridH2Row> find(GridSearchRowPointer lower, GridSearchRowPointer upper)
-            throws IgniteCheckedException {
-
-            Collection<GridH2Row> rows;
-
-            if (lower == null && upper == null)
-                rows = tree.values();
-            else if (lower != null && upper == null)
-                rows = tree.tailMap(lower).values();
-            else if (lower == null)
-                rows = tree.headMap(upper).values();
-            else
-                rows = tree.subMap(lower, false, upper, false).values();
-
-            return new GridCursorIteratorWrapper<>(rows.iterator());
-        }
-
-        /** {@inheritDoc} */
-        @Override public GridH2Row findFirst() throws IgniteCheckedException {
-            Map.Entry<GridSearchRowPointer, GridH2Row> first = tree.firstEntry();
-            return (first == null) ? null : first.getValue();
-        }
-
-        /** {@inheritDoc} */
-        @Override public GridH2Row findLast() throws IgniteCheckedException {
-            Map.Entry<GridSearchRowPointer, GridH2Row> last = tree.lastEntry();
-            return (last == null) ? null : last.getValue();
-        }
-
-        /** {@inheritDoc} */
-        @Override public GridH2Row remove(GridSearchRowPointer key) {
-            return tree.remove(key);
-        }
-
-        /** {@inheritDoc} */
-        @Override public long size() {
-            return tree.size();
-        }
-
-        /** {@inheritDoc} */
-        @Override public IgniteNavigableMapTree clone() {
-            IgniteNavigableMapTree cp;
-
-            try {
-                cp = (IgniteNavigableMapTree)super.clone();
-            }
-            catch (final CloneNotSupportedException e) {
-                throw DbException.convert(e);
-            }
-
-            return new IgniteNavigableMapTree(cp.tree);
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
index 19b628b..e717367 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
@@ -26,7 +26,6 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentMap;
@@ -59,7 +58,6 @@ import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 import org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RetryException;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryCancelRequest;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryFailResponse;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryNextPageRequest;
@@ -545,22 +543,6 @@ public class GridMapQueryExecutor {
                 .topologyVersion(topVer)
                 .reservations(reserved);
 
-            List<GridH2Table> snapshotedTbls = null;
-
-            if (!F.isEmpty(tbls)) {
-                snapshotedTbls = new ArrayList<>(tbls.size());
-
-                for (QueryTable tbl : tbls) {
-                    GridH2Table h2Tbl = h2.dataTable(tbl);
-
-                    Objects.requireNonNull(h2Tbl, tbl.toString());
-
-                    h2Tbl.snapshotIndexes(qctx, segmentId);
-
-                    snapshotedTbls.add(h2Tbl);
-                }
-            }
-
             Connection conn = h2.connectionForSchema(schemaName);
 
             H2Utils.setupConnection(conn, distributedJoinMode != OFF, enforceJoinOrder);
@@ -596,8 +578,6 @@ public class GridMapQueryExecutor {
                             qr.queryCancel(qryIdx));
 
                         if (evt) {
-                            assert mainCctx != null;
-
                             ctx.event().record(new CacheQueryExecutedEvent<>(
                                 node,
                                 "SQL query executed.",
@@ -635,11 +615,6 @@ public class GridMapQueryExecutor {
 
                 if (distributedJoinMode == OFF)
                     qctx.clearContext(false);
-
-                if (!F.isEmpty(snapshotedTbls)) {
-                    for (GridH2Table dataTbl : snapshotedTbls)
-                        dataTbl.releaseSnapshots();
-                }
             }
         }
         catch (Throwable e) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c77b869/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TableSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TableSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TableSelfTest.java
index 88ff61e..a1a64e8 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TableSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/opt/GridH2TableSelfTest.java
@@ -18,38 +18,20 @@
 package org.apache.ignite.internal.processors.query.h2.opt;
 
 import java.sql.Connection;
-import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashSet;
 import java.util.Random;
-import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.processors.query.h2.database.H2PkHashIndex;
-import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory;
-import org.apache.ignite.internal.util.lang.GridCursor;
-import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
-import org.h2.Driver;
-import org.h2.index.Cursor;
-import org.h2.index.Index;
-import org.h2.result.Row;
-import org.h2.result.SearchRow;
-import org.h2.result.SortOrder;
-import org.h2.table.IndexColumn;
 import org.h2.value.ValueLong;
 import org.h2.value.ValueString;
 import org.h2.value.ValueTimestamp;
 import org.h2.value.ValueUuid;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * Tests H2 Table.
@@ -173,47 +155,6 @@ public class GridH2TableSelfTest extends GridCommonAbstractTest {
             assertEquals(MAX_X, idx.getRowCount(null));
         }
 
-        // Check correct rows order.
-        checkOrdered((GridH2TreeIndex)tbl.indexes().get(0), new Comparator<SearchRow>() {
-            @Override public int compare(SearchRow o1, SearchRow o2) {
-                UUID id1 = (UUID)o1.getValue(0).getObject();
-                UUID id2 = (UUID)o2.getValue(0).getObject();
-
-                return id1.compareTo(id2);
-            }
-        });
-
-        checkOrdered((GridH2TreeIndex)tbl.indexes().get(1), new Comparator<SearchRow>() {
-            @Override public int compare(SearchRow o1, SearchRow o2) {
-                Long x1 = (Long)o1.getValue(3).getObject();
-                Long x2 = (Long)o2.getValue(3).getObject();
-
-                int c = x2.compareTo(x1);
-
-                if (c != 0)
-                    return c;
-
-                Timestamp t1 = (Timestamp)o1.getValue(1).getObject();
-                Timestamp t2 = (Timestamp)o2.getValue(1).getObject();
-
-                return t1.compareTo(t2);
-            }
-        });
-
-        checkOrdered((GridH2TreeIndex)tbl.indexes().get(2), new Comparator<SearchRow>() {
-            @Override public int compare(SearchRow o1, SearchRow o2) {
-                String s1 = (String)o1.getValue(2).getObject();
-                String s2 = (String)o2.getValue(2).getObject();
-
-                return s2.compareTo(s1);
-            }
-        });
-
-        // Indexes data consistency.
-        ArrayList<? extends Index> idxs = tbl.indexes();
-
-        checkIndexesConsistent((ArrayList<Index>)idxs, null);
-
         // Check unique index.
         UUID id = UUID.randomUUID();
         UUID id2 = UUID.randomUUID();
@@ -405,54 +346,6 @@ public class GridH2TableSelfTest extends GridCommonAbstractTest {
 
 
     /**
-     * @throws Exception If failed.
-     */
-    public void testIndexFindFirstOrLast() throws Exception {
-        Index index = tbl.getIndexes().get(2);
-        assertTrue(index instanceof GridH2TreeIndex);
-        assertTrue(index.canGetFirstOrLast());
-
-        //find first on empty data
-        Cursor cursor = index.findFirstOrLast(null, true);
-        assertFalse(cursor.next());
-        assertNull(cursor.get());
-
-        //find last on empty data
-        cursor = index.findFirstOrLast(null, false);
-        assertFalse(cursor.next());
-        assertNull(cursor.get());
-
-        //fill with data
-        int rows = 100;
-        long t = System.currentTimeMillis();
-        Random rnd = new Random();
-        UUID min = null;
-        UUID max = null;
-
-        for (int i = 0 ; i < rows; i++) {
-            UUID id = UUID.randomUUID();
-            if (min == null || id.compareTo(min) < 0)
-                min = id;
-            if (max == null || id.compareTo(max) > 0)
-                max = id;
-            GridH2Row row = row(id, t++, id.toString(), rnd.nextInt(100));
-            ((GridH2TreeIndex)index).put(row);
-        }
-
-        //find first
-        cursor = index.findFirstOrLast(null, true);
-        assertTrue(cursor.next());
-        assertEquals(min, cursor.get().getValue(0).getObject());
-        assertFalse(cursor.next());
-
-        //find last
-        cursor = index.findFirstOrLast(null, false);
-        assertTrue(cursor.next());
-        assertEquals(max, cursor.get().getValue(0).getObject());
-        assertFalse(cursor.next());
-    }
-
-    /**
      * Check query plan to correctly select index.
      *
      * @param conn Connection.
@@ -473,69 +366,4 @@ public class GridH2TableSelfTest extends GridCommonAbstractTest {
             }
         }
     }
-
-    /**
-     * @param idxs Indexes.
-     * @param rowSet Rows.
-     * @return Rows.
-     */
-    private Set<Row> checkIndexesConsistent(ArrayList<Index> idxs, @Nullable Set<Row> rowSet) throws IgniteCheckedException {
-        for (Index idx : idxs) {
-            if (!(idx instanceof GridH2TreeIndex))
-                continue;
-
-            Set<Row> set = new HashSet<>();
-
-            GridCursor<GridH2Row> cursor = ((GridH2TreeIndex)idx).rows();
-
-            while(cursor.next())
-                assertTrue(set.add(cursor.get()));
-
-            //((GridH2SnapTreeSet)((GridH2Index)idx).tree).print();
-
-            if (rowSet == null || rowSet.isEmpty())
-                rowSet = set;
-            else
-                assertEquals(rowSet, set);
-        }
-
-        return rowSet;
-    }
-
-    /**
-     * @param idxs Indexes list.
-     */
-    private void checkOrdered(ArrayList<Index> idxs) throws IgniteCheckedException {
-        for (Index idx : idxs) {
-            if (!(idx instanceof GridH2TreeIndex))
-                continue;
-
-            GridH2TreeIndex h2Idx = (GridH2TreeIndex)idx;
-
-            checkOrdered(h2Idx, h2Idx);
-        }
-    }
-
-    /**
-     * @param idx Index.
-     * @param cmp Comparator.
-     */
-    private void checkOrdered(GridH2TreeIndex idx, Comparator<? super GridH2Row> cmp) throws IgniteCheckedException {
-        GridCursor<GridH2Row> cursor = idx.rows();
-
-        GridH2Row min = null;
-
-        while (cursor.next()) {
-            GridH2Row row = cursor.get();
-
-            System.out.println(row);
-
-            assertNotNull(row);
-
-            assertFalse("Incorrect row order in index: " + idx + "\n min: " + min + "\n row: " + row,
-                min != null && cmp.compare(min, row) > 0);
-
-            min = row;
-        }
-    }
 }
\ No newline at end of file


[22/29] ignite git commit: IGNITE-5741 - Replaced HeapByteBuffer with DirectByteBuffer in WAL records iterator - Fixes #2329.

Posted by nt...@apache.org.
IGNITE-5741 - Replaced HeapByteBuffer with DirectByteBuffer in WAL records iterator - Fixes #2329.

Signed-off-by: Alexey Goncharuk <al...@gmail.com>


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

Branch: refs/heads/ignite-5947
Commit: c23a2dcfb1395e87cb4e14457a053c6b4727b318
Parents: 13f38d7
Author: Dmitriy Govorukhin <dm...@gmail.com>
Authored: Mon Aug 14 16:33:12 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Mon Aug 14 16:41:34 2017 +0300

----------------------------------------------------------------------
 .../wal/AbstractWalRecordsIterator.java         | 11 ++++-
 .../persistence/wal/ByteBufferExpander.java     | 22 ++++++---
 .../wal/FileWriteAheadLogManager.java           | 11 ++---
 .../reader/StandaloneWalRecordsIterator.java    |  9 ++--
 .../apache/ignite/internal/util/GridUnsafe.java | 14 ++++++
 .../db/wal/crc/IgniteDataIntegrityTests.java    | 52 +++++++++++++++++++-
 6 files changed, 100 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/c23a2dcf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
index beed90b..db949c3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
@@ -95,7 +95,6 @@ public abstract class AbstractWalRecordsIterator
         this.serializer = serializer;
         this.ioFactory = ioFactory;
 
-        // Do not allocate direct buffer for iterator.
         buf = new ByteBufferExpander(bufSize, ByteOrder.nativeOrder());
     }
 
@@ -128,6 +127,16 @@ public abstract class AbstractWalRecordsIterator
         return curRec != null;
     }
 
+    /** {@inheritDoc} */
+    @Override protected void onClose() throws IgniteCheckedException {
+        try {
+            buf.close();
+        }
+        catch (Exception ex) {
+            throw new IgniteCheckedException(ex);
+        }
+    }
+
     /**
      * Switches records iterator to the next record.
      * <ul>

http://git-wip-us.apache.org/repos/asf/ignite/blob/c23a2dcf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/ByteBufferExpander.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/ByteBufferExpander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/ByteBufferExpander.java
index 829cd5c..cf1db84 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/ByteBufferExpander.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/ByteBufferExpander.java
@@ -19,19 +19,24 @@ package org.apache.ignite.internal.processors.cache.persistence.wal;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import org.apache.ignite.internal.util.GridUnsafe;
 
 /**
  * ByteBuffer wrapper for dynamically expand buffer size.
  */
-public class ByteBufferExpander {
+public class ByteBufferExpander implements AutoCloseable {
     /** Byte buffer */
     private ByteBuffer buf;
 
+    /**
+     * @param initSize Initial size.
+     * @param order Byte order.
+     */
     public ByteBufferExpander(int initSize, ByteOrder order) {
-        ByteBuffer buffer = ByteBuffer.allocate(initSize);
+        ByteBuffer buffer = GridUnsafe.allocateBuffer(initSize);
         buffer.order(order);
 
-        this.buf = buffer;
+        buf = buffer;
     }
 
     /**
@@ -49,16 +54,17 @@ public class ByteBufferExpander {
      * @return ByteBuffer with requested size.
      */
     public ByteBuffer expand(int size) {
-        ByteBuffer newBuf = ByteBuffer.allocate(size);
+        ByteBuffer newBuf = GridUnsafe.reallocateBuffer(buf, size);
 
         newBuf.order(buf.order());
 
-        newBuf.put(buf);
-
-        newBuf.flip();
-
         buf = newBuf;
 
         return newBuf;
     }
+
+    /** {@inheritDoc} */
+    @Override public void close() {
+        GridUnsafe.freeBuffer(buf);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/c23a2dcf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
index 17db8f8..bb1f910 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
@@ -1430,12 +1430,8 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
      */
     private int readSerializerVersion(FileIO io, File file, long idx)
         throws IOException, IgniteCheckedException {
-        try {
-            ByteBuffer buf = ByteBuffer.allocate(RecordV1Serializer.HEADER_RECORD_SIZE);
-            buf.order(ByteOrder.nativeOrder());
-
-            FileInput in = new FileInput(io,
-                new ByteBufferExpander(RecordV1Serializer.HEADER_RECORD_SIZE, ByteOrder.nativeOrder()));
+        try (ByteBufferExpander buf = new ByteBufferExpander(RecordV1Serializer.HEADER_RECORD_SIZE, ByteOrder.nativeOrder())){
+            FileInput in = new FileInput(io, buf);
 
             // Header record must be agnostic to the serializer version.
             WALRecord rec = serializer.readRecord(in, new FileWALPointer(idx, 0, 0));
@@ -2402,9 +2398,12 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
 
         /** {@inheritDoc} */
         @Override protected void onClose() throws IgniteCheckedException {
+            super.onClose();
+
             curRec = null;
 
             final ReadFileHandle handle = closeCurrentWalSegment();
+
             if (handle != null && handle.workDir)
                 releaseWorkSegment(curWalSegmIdx);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/c23a2dcf/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
index 85022ad..cd0f8ab 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneWalRecordsIterator.java
@@ -180,9 +180,11 @@ class StandaloneWalRecordsIterator extends AbstractWalRecordsIterator {
 
             FileWALPointer ptr;
 
-            try (FileIO fileIO = ioFactory.create(file, "r")) {
-                final DataInput in = new FileInput(fileIO,
-                    new ByteBufferExpander(HEADER_RECORD_SIZE, ByteOrder.nativeOrder()));
+            try (
+                FileIO fileIO = ioFactory.create(file, "r");
+                ByteBufferExpander buf = new ByteBufferExpander(HEADER_RECORD_SIZE, ByteOrder.nativeOrder())
+            ) {
+                final DataInput in = new FileInput(fileIO, buf);
 
                 // Header record must be agnostic to the serializer version.
                 final int type = in.readUnsignedByte();
@@ -256,6 +258,7 @@ class StandaloneWalRecordsIterator extends AbstractWalRecordsIterator {
     /** {@inheritDoc} */
     @Override protected void onClose() throws IgniteCheckedException {
         super.onClose();
+
         curRec = null;
 
         closeCurrentWalSegment();

http://git-wip-us.apache.org/repos/asf/ignite/blob/c23a2dcf/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
index 0add64d..15e6f2c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
@@ -139,6 +139,20 @@ public abstract class GridUnsafe {
     }
 
     /**
+     *
+     * @param buf Buffer.
+     * @param len New length.
+     * @return Reallocated direct buffer.
+     */
+    public static ByteBuffer reallocateBuffer(ByteBuffer buf, int len) {
+        long ptr = bufferAddress(buf);
+
+        long newPtr = reallocateMemory(ptr, len);
+
+        return wrapPointer(newPtr, len);
+    }
+
+    /**
      * Gets boolean value from object field.
      *
      * @param obj Object.

http://git-wip-us.apache.org/repos/asf/ignite/blob/c23a2dcf/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteDataIntegrityTests.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteDataIntegrityTests.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteDataIntegrityTests.java
index b93c74d..270c560 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteDataIntegrityTests.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/crc/IgniteDataIntegrityTests.java
@@ -41,6 +41,9 @@ public class IgniteDataIntegrityTests extends TestCase {
     /** Random access file. */
     private RandomAccessFile randomAccessFile;
 
+    /** Buffer expander. */
+    private ByteBufferExpander expBuf;
+
     /** {@inheritDoc} */
     @Override protected void setUp() throws Exception {
         super.setUp();
@@ -50,9 +53,11 @@ public class IgniteDataIntegrityTests extends TestCase {
 
         randomAccessFile = new RandomAccessFile(file, "rw");
 
+        expBuf = new ByteBufferExpander(1024, ByteOrder.BIG_ENDIAN);
+
         fileInput = new FileInput(
             new RandomAccessFileIO(randomAccessFile),
-            new ByteBufferExpander(1024, ByteOrder.BIG_ENDIAN)
+            expBuf
         );
 
         ByteBuffer buf = ByteBuffer.allocate(1024);
@@ -70,6 +75,12 @@ public class IgniteDataIntegrityTests extends TestCase {
         randomAccessFile.getFD().sync();
     }
 
+    /** {@inheritDoc} */
+    @Override protected void tearDown() throws Exception {
+        randomAccessFile.close();
+        expBuf.close();
+    }
+
     /**
      *
      */
@@ -108,6 +119,45 @@ public class IgniteDataIntegrityTests extends TestCase {
     }
 
     /**
+     *
+     */
+    public void testExpandBuffer() {
+        ByteBufferExpander expBuf = new ByteBufferExpander(16, ByteOrder.nativeOrder());
+
+        ByteBuffer b1 = expBuf.buffer();
+
+        b1.put((byte)1);
+        b1.putInt(2);
+        b1.putLong(3L);
+
+        assertEquals(13, b1.position());
+        assertEquals(16, b1.limit());
+
+        ByteBuffer b2 = expBuf.expand(32);
+
+        assertEquals(0, b2.position());
+        assertEquals((byte)1, b2.get());
+        assertEquals(2, b2.getInt());
+        assertEquals(3L, b2.getLong());
+        assertEquals(13, b2.position());
+        assertEquals(32, b2.limit());
+
+        b2.putInt(4);
+
+        assertEquals(17, b2.position());
+        assertEquals(32, b2.limit());
+
+        b2.flip();
+
+        assertEquals(0, b2.position());
+        assertEquals((byte)1, b2.get());
+        assertEquals(2, b2.getInt());
+        assertEquals(3L, b2.getLong());
+        assertEquals(4, b2.getInt());
+        assertEquals(17, b2.limit());
+    }
+
+    /**
      * @param rangeFrom Range from.
      * @param rangeTo Range to.
      */


[25/29] ignite git commit: IGNITE-6052 request cluster state from daemon node via compute grid - Fixes #2439.

Posted by nt...@apache.org.
IGNITE-6052 request cluster state from daemon node via compute grid - Fixes #2439.

Signed-off-by: Alexey Goncharuk <al...@gmail.com>


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

Branch: refs/heads/ignite-5947
Commit: 305c0f4ffb745bdc04cd0a6f3b45dbd9ff5da302
Parents: cdac5a8
Author: Dmitriy Govorukhin <dm...@gmail.com>
Authored: Mon Aug 14 17:47:11 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Mon Aug 14 17:48:35 2017 +0300

----------------------------------------------------------------------
 .../cluster/GridClusterStateProcessor.java      | 64 +++++++++++++++++---
 .../IgniteStandByClusterTest.java               | 48 ++++++++++++---
 2 files changed, 94 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/305c0f4f/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
index 283a58f..13a889c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/GridClusterStateProcessor.java
@@ -55,6 +55,7 @@ import org.apache.ignite.internal.util.typedef.CI2;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteCallable;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgniteRunnable;
 import org.apache.ignite.resources.IgniteInstanceResource;
@@ -119,6 +120,9 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
      * @return Cluster state to be used on public API.
      */
     public boolean publicApiActiveState() {
+        if (ctx.isDaemon())
+            return sendComputeCheckGlobalState();
+
         DiscoveryDataClusterState globalState = this.globalState;
 
         assert globalState != null;
@@ -407,7 +411,7 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
         if (ctx.isDaemon() || ctx.clientNode()) {
             GridFutureAdapter<Void> fut = new GridFutureAdapter<>();
 
-            sendCompute(activate, fut);
+            sendComputeChangeGlobalState(activate, fut);
 
             return fut;
         }
@@ -490,11 +494,9 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
      * @param activate New cluster state.
      * @param resFut State change future.
      */
-    private void sendCompute(boolean activate, final GridFutureAdapter<Void> resFut) {
+    private void sendComputeChangeGlobalState(boolean activate, final GridFutureAdapter<Void> resFut) {
         AffinityTopologyVersion topVer = ctx.discovery().topologyVersionEx();
 
-        IgniteCompute comp = ((ClusterGroupAdapter)ctx.cluster().get().forServers()).compute();
-
         if (log.isInfoEnabled()) {
             log.info("Sending " + prettyStr(activate) + " request from node [id=" + ctx.localNodeId() +
                 ", topVer=" + topVer +
@@ -502,7 +504,9 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
                 ", daemon" + ctx.isDaemon() + "]");
         }
 
-        IgniteFuture<Void> fut = comp.runAsync(new ClientChangeGlobalStateComputeRequest(activate));
+        IgniteCompute comp = ((ClusterGroupAdapter)ctx.cluster().get().forServers()).compute();
+
+        IgniteFuture<Void> fut = comp.runAsync(new ChangeGlobalStateComputeRequest(activate));
 
         fut.listen(new CI1<IgniteFuture>() {
             @Override public void apply(IgniteFuture fut) {
@@ -519,6 +523,32 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
     }
 
     /**
+     *  Check cluster state.
+     *
+     *  @return Cluster state, {@code True} if cluster active, {@code False} if inactive.
+     */
+    private boolean sendComputeCheckGlobalState() {
+        AffinityTopologyVersion topVer = ctx.discovery().topologyVersionEx();
+
+        if (log.isInfoEnabled()) {
+            log.info("Sending check cluster state request from node [id=" + ctx.localNodeId() +
+                ", topVer=" + topVer +
+                ", client=" + ctx.clientNode() +
+                ", daemon" + ctx.isDaemon() + "]");
+        }
+        IgniteCompute comp = ((ClusterGroupAdapter)ctx.cluster().get().forServers()).compute();
+
+        return comp.call(new IgniteCallable<Boolean>() {
+            @IgniteInstanceResource
+            private Ignite ig;
+
+            @Override public Boolean call() throws Exception {
+                return ig.active();
+            }
+        });
+    }
+
+    /**
      * @param errs Errors.
      * @param req State change request.
      */
@@ -854,7 +884,7 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
     /**
      *
      */
-    private static class ClientChangeGlobalStateComputeRequest implements IgniteRunnable {
+    private static class ChangeGlobalStateComputeRequest implements IgniteRunnable {
         /** */
         private static final long serialVersionUID = 0L;
 
@@ -863,18 +893,34 @@ public class GridClusterStateProcessor extends GridProcessorAdapter {
 
         /** Ignite. */
         @IgniteInstanceResource
-        private Ignite ignite;
+        private Ignite ig;
 
         /**
          * @param activate New cluster state.
          */
-        private ClientChangeGlobalStateComputeRequest(boolean activate) {
+        private ChangeGlobalStateComputeRequest(boolean activate) {
             this.activate = activate;
         }
 
         /** {@inheritDoc} */
         @Override public void run() {
-            ignite.active(activate);
+            ig.active(activate);
+        }
+    }
+
+    /**
+     *
+     */
+    private static class CheckGlobalStateComputeRequest implements IgniteCallable<Boolean> {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** Ignite. */
+        @IgniteInstanceResource
+        private Ignite ig;
+
+        @Override public Boolean call() throws Exception {
+            return ig.active();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/305c0f4f/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteStandByClusterTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteStandByClusterTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteStandByClusterTest.java
index 30fff08..c2bece0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteStandByClusterTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/standbycluster/IgniteStandByClusterTest.java
@@ -252,6 +252,36 @@ public class IgniteStandByClusterTest extends GridCommonAbstractTest {
     /**
      * @throws Exception if fail.
      */
+    public void testCheckStatusFromDaemon() throws Exception {
+        IgniteEx ig = startGrid(0);
+
+        assertFalse(ig.active());
+
+        ig.active(true);
+
+        IgniteEx daemon = startGrid(
+            getConfiguration("daemon")
+                .setDaemon(true)
+                .setClientMode(true)
+        );
+
+        assertTrue(ig.active());
+        assertTrue(daemon.active());
+
+        daemon.active(false);
+
+        assertFalse(ig.active());
+        assertFalse(daemon.active());
+
+        daemon.active(true);
+
+        assertTrue(ig.active());
+        assertTrue(daemon.active());
+    }
+
+    /**
+     * @throws Exception if fail.
+     */
     public void testRestartCluster() throws Exception {
         IgniteEx ig1 = startGrid(getConfiguration("node1"));
         IgniteEx ig2 = startGrid(getConfiguration("node2"));
@@ -298,25 +328,25 @@ public class IgniteStandByClusterTest extends GridCommonAbstractTest {
 
         ig1.active(true);
 
-        checkPlugin(ig1,1,0);
-        checkPlugin(ig2,1,0);
-        checkPlugin(ig3,1,0);
+        checkPlugin(ig1, 1, 0);
+        checkPlugin(ig2, 1, 0);
+        checkPlugin(ig3, 1, 0);
 
         ig2.active(false);
 
         ig3.active(true);
 
-        checkPlugin(ig1,2,1);
-        checkPlugin(ig2,2,1);
-        checkPlugin(ig3,2,1);
+        checkPlugin(ig1, 2, 1);
+        checkPlugin(ig2, 2, 1);
+        checkPlugin(ig3, 2, 1);
 
         ig1.active(false);
 
         ig2.active(true);
 
-        checkPlugin(ig1,3,2);
-        checkPlugin(ig2,3,2);
-        checkPlugin(ig3,3,2);
+        checkPlugin(ig1, 3, 2);
+        checkPlugin(ig2, 3, 2);
+        checkPlugin(ig3, 3, 2);
 
     }
 


[06/29] ignite git commit: Merge remote-tracking branch 'upstream/ignite-2.1.4' into ignite-2.1.4

Posted by nt...@apache.org.
Merge remote-tracking branch 'upstream/ignite-2.1.4' into ignite-2.1.4


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

Branch: refs/heads/ignite-5947
Commit: d1a74a4be8744528e6ed23706174041ddb0f2618
Parents: 0f22223 772d462
Author: devozerov <vo...@gridgain.com>
Authored: Fri Aug 4 12:04:38 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Fri Aug 4 12:04:38 2017 +0300

----------------------------------------------------------------------
 .../ignite/tests/utils/TestTransaction.java     |  10 +
 .../apache/ignite/IgniteSystemProperties.java   |   6 +
 .../IgniteDiagnosticPrepareContext.java         |   3 +-
 .../apache/ignite/internal/IgniteKernal.java    |   3 +-
 .../mem/file/MappedFileMemoryProvider.java      |   3 +-
 .../GridCachePartitionExchangeManager.java      |   2 +-
 .../processors/cache/GridCacheProcessor.java    |  16 +-
 .../cache/GridCacheSharedContext.java           |  24 +
 .../processors/cache/GridCacheUtils.java        |   7 +-
 .../cache/IgniteCacheOffheapManagerImpl.java    |  26 +-
 .../processors/cache/IgniteCacheProxyImpl.java  |  24 +-
 .../GridDhtPartitionsExchangeFuture.java        |  20 +-
 .../cache/distributed/near/GridNearTxLocal.java |  51 ++
 .../GridCacheDatabaseSharedManager.java         |   7 +-
 .../persistence/freelist/FreeListImpl.java      |  18 +-
 .../wal/FileWriteAheadLogManager.java           |  37 +-
 .../reader/StandaloneWalRecordsIterator.java    |   4 +-
 .../store/GridCacheStoreManagerAdapter.java     |  10 +
 .../cache/transactions/IgniteTxAdapter.java     |  20 +-
 .../cache/transactions/IgniteTxManager.java     |  74 ++
 .../cache/transactions/IgniteTxMap.java         |   2 +-
 .../transactions/TransactionProxyImpl.java      |  46 +-
 .../cluster/GridClusterStateProcessor.java      |   3 +-
 .../datastructures/GridCacheLockImpl.java       |  13 +-
 .../processors/odbc/SqlListenerProcessor.java   |   3 +-
 .../ignite/internal/util/nio/GridNioServer.java |   7 +-
 .../internal/visor/debug/VisorThreadInfo.java   |  10 +-
 .../internal/visor/query/VisorQueryTask.java    |   2 +-
 .../visor/query/VisorScanQueryTask.java         |   2 +-
 .../ignite/spi/discovery/tcp/ServerImpl.java    |  38 +-
 .../apache/ignite/transactions/Transaction.java |  14 +
 .../ignite/transactions/TransactionState.java   |   7 +-
 .../cache/store/jdbc/model/BinaryTest.java      |   1 -
 .../processors/cache/IgniteCacheGroupsTest.java |  22 +-
 ...ptimisticTxSuspendResumeMultiServerTest.java |  30 +
 .../IgniteOptimisticTxSuspendResumeTest.java    | 751 +++++++++++++++++++
 .../IgnitePessimisticTxSuspendResumeTest.java   |  91 +++
 .../IgnitePdsCacheRebalancingAbstractTest.java  |   2 +
 .../TxOptimisticDeadlockDetectionTest.java      |   2 +
 .../ignite/testframework/GridTestUtils.java     |  26 +
 .../cache/GridAbstractCacheStoreSelfTest.java   |  10 +
 .../testsuites/IgniteCacheTestSuite6.java       |  42 ++
 .../ignite/tests/p2p/JobStealingTask.java       |  12 +-
 .../org/apache/ignite/tests/p2p/NodeFilter.java |  30 +
 .../hadoop/jobtracker/HadoopJobTracker.java     |  24 +-
 .../hadoop/shuffle/HadoopShuffleJob.java        |   5 +-
 .../processors/query/h2/IgniteH2Indexing.java   |  21 +-
 .../cache/index/H2DynamicTableSelfTest.java     |  32 +
 .../processors/cache/jta/CacheJtaManager.java   |   5 +-
 .../processors/cache/jta/CacheJtaResource.java  |  28 +-
 .../GridJtaTransactionManagerSelfTest.java      | 208 +++++
 .../ignite/testsuites/IgniteJtaTestSuite.java   |   5 +-
 .../apache/ignite/stream/mqtt/MqttStreamer.java |   6 +-
 .../include/ignite/binary/binary_writer.h       |   4 +-
 .../ignite/impl/binary/binary_reader_impl.h     |  50 +-
 .../ignite/impl/binary/binary_type_impl.h       |  67 ++
 .../ignite/impl/binary/binary_writer_impl.h     |  43 +-
 .../src/impl/binary/binary_reader_impl.cpp      |  63 +-
 .../src/impl/binary/binary_writer_impl.cpp      |  41 +-
 .../core-test/config/cache-query-default.xml    |  29 +
 .../src/binary_reader_writer_raw_test.cpp       |  36 +
 .../core-test/src/binary_reader_writer_test.cpp | 135 +++-
 .../cpp/core-test/src/cache_query_test.cpp      | 215 +++++-
 .../cpp/core-test/src/cluster_test.cpp          |  13 +
 .../ignite/cache/query/query_fields_row.h       |  28 +
 .../ignite/cache/query/query_sql_fields.h       |  13 +-
 .../platforms/cpp/core/include/ignite/ignite.h  |  15 +
 .../ignite/impl/cache/query/query_argument.h    |  63 ++
 .../impl/cache/query/query_fields_row_impl.h    |  29 +
 .../ignite/impl/cluster/cluster_group_impl.h    |  15 +
 .../cpp/core/include/ignite/impl/ignite_impl.h  |  24 +-
 modules/platforms/cpp/core/src/ignite.cpp       |  10 +
 .../src/impl/cluster/cluster_group_impl.cpp     |  26 +-
 .../platforms/cpp/core/src/impl/ignite_impl.cpp |   4 +
 .../spi/deployment/uri/UriDeploymentSpi.java    |   3 +-
 modules/web-console/backend/app/mongo.js        |   2 +-
 modules/web-console/backend/app/settings.js     |   3 +-
 modules/web-console/backend/index.js            |  16 +-
 modules/web-console/backend/middlewares/api.js  |  39 +-
 .../web-console/backend/services/activities.js  |  12 +-
 modules/web-console/frontend/app/app.js         |  10 +-
 .../components/grid-item-selected/component.js  |  28 +
 .../components/grid-item-selected/controller.js |  38 +
 .../app/components/grid-item-selected/index.js  |  24 +
 .../components/grid-item-selected/template.pug  |  17 +
 .../list-of-registered-users.tpl.pug            |   4 +-
 .../app/components/ui-grid-hovering/cell.js     |  48 ++
 .../app/components/ui-grid-hovering/hovering.js |  31 +
 .../app/components/ui-grid-hovering/index.js    |  30 +
 .../app/components/ui-grid-hovering/style.scss  |  22 +
 .../app/components/ui-grid-hovering/viewport.js |  42 ++
 .../frontend/app/controllers/auth.controller.js |   9 +-
 .../app/modules/agent/AgentManager.service.js   |  24 +-
 .../app/modules/agent/AgentModal.service.js     |   8 +-
 .../configuration/generator/Maven.service.js    |  13 +-
 .../frontend/app/modules/demo/Demo.module.js    |  22 +-
 .../frontend/app/modules/sql/sql.controller.js  |  11 +-
 .../states/configuration/clusters/hadoop.pug    |   2 +-
 .../configuration/summary/summary.worker.js     |   4 +-
 .../frontend/app/modules/states/errors.state.js |   2 +-
 .../app/modules/states/password.state.js        |   2 +
 .../app/modules/states/profile.state.js         |   2 +-
 .../frontend/app/modules/states/signin.state.js |   6 +-
 .../app/modules/user/AclRoute.provider.js       |  50 --
 .../frontend/app/modules/user/user.module.js    |  35 +-
 .../frontend/app/services/Messages.service.js   |   7 +
 .../web-console/frontend/views/signin.tpl.pug   |   2 +-
 .../views/templates/agent-download.tpl.pug      |   2 -
 108 files changed, 2918 insertions(+), 440 deletions(-)
----------------------------------------------------------------------



[24/29] ignite git commit: IGNITE-5843 Persist cache configuration received on node join - Fixes #2347.

Posted by nt...@apache.org.
IGNITE-5843 Persist cache configuration received on node join - Fixes #2347.


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

Branch: refs/heads/ignite-5947
Commit: cdac5a87cb1432ffd0ec32a2888505805e7348da
Parents: 2f38065
Author: EdShangGG <es...@gridgain.com>
Authored: Mon Aug 14 16:56:11 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Mon Aug 14 17:32:01 2017 +0300

----------------------------------------------------------------------
 .../cache/CacheAffinitySharedManager.java       | 56 +++++++++++++++-----
 .../GridCacheDatabaseSharedManager.java         | 15 +++---
 .../persistence/file/FilePageStoreManager.java  |  1 -
 .../processors/query/GridQueryProcessor.java    | 15 ------
 .../persistence/IgnitePdsDynamicCacheTest.java  | 43 +++++++++++++++
 5 files changed, 92 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/cdac5a87/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
index d251d52..9fc791e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java
@@ -720,13 +720,6 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
             }
 
             try {
-                // Save configuration before cache started.
-                if (cctx.pageStore() != null && !cctx.kernalContext().clientNode()) {
-                    cctx.pageStore().storeCacheData(
-                        new StoredCacheData(req.startCacheConfiguration())
-                    );
-                }
-
                 if (startCache) {
                     cctx.cache().prepareCacheStart(req.startCacheConfiguration(),
                         cacheDesc,
@@ -2157,7 +2150,7 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
     /**
      *
      */
-    static class CachesInfo {
+    class CachesInfo {
         /** Registered cache groups (updated from exchange thread). */
         private final ConcurrentHashMap<Integer, CacheGroupDescriptor> registeredGrps = new ConcurrentHashMap<>();
 
@@ -2170,10 +2163,29 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
          */
         void init(Map<Integer, CacheGroupDescriptor> grps, Map<String, DynamicCacheDescriptor> caches) {
             for (CacheGroupDescriptor grpDesc : grps.values())
-                registeredGrps.put(grpDesc.groupId(), grpDesc);
+                registerGroup(grpDesc);
 
             for (DynamicCacheDescriptor cacheDesc : caches.values())
-                registeredCaches.put(cacheDesc.cacheId(), cacheDesc);
+                registerCache(cacheDesc);
+        }
+
+
+        /**
+         * @param desc Description.
+         */
+        private DynamicCacheDescriptor registerCache(DynamicCacheDescriptor desc) {
+            saveCacheConfiguration(desc.cacheConfiguration());
+
+            return registeredCaches.put(desc.cacheId(), desc);
+        }
+
+        /**
+         * @param grpDesc Group description.
+         */
+        private CacheGroupDescriptor registerGroup(CacheGroupDescriptor grpDesc) {
+            saveCacheConfiguration(grpDesc.config());
+
+            return registeredGrps.put(grpDesc.groupId(), grpDesc);
         }
 
         /**
@@ -2203,10 +2215,10 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
                 CacheGroupDescriptor grpDesc = desc.groupDescriptor();
 
                 if (!registeredGrps.containsKey(grpDesc.groupId()))
-                    registeredGrps.put(grpDesc.groupId(), grpDesc);
+                    registerGroup(grpDesc);
 
                 if (!registeredCaches.containsKey(desc.cacheId()))
-                    registeredCaches.put(desc.cacheId(), desc);
+                    registerCache(desc);
             }
         }
 
@@ -2221,7 +2233,7 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
             }
 
             for (ExchangeActions.CacheGroupActionData startAction : exchActions.cacheGroupsToStart()) {
-                CacheGroupDescriptor old = registeredGrps.put(startAction.descriptor().groupId(), startAction.descriptor());
+                CacheGroupDescriptor old = registerGroup(startAction.descriptor());
 
                 assert old == null : old;
             }
@@ -2230,7 +2242,7 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
                 registeredCaches.remove(req.descriptor().cacheId());
 
             for (ExchangeActions.CacheActionData req : exchActions.cacheStartRequests())
-                registeredCaches.put(req.descriptor().cacheId(), req.descriptor());
+                registerCache(req.descriptor());
         }
 
         /**
@@ -2250,4 +2262,20 @@ public class CacheAffinitySharedManager<K, V> extends GridCacheSharedManagerAdap
             registeredCaches.clear();
         }
     }
+
+    /**
+     * @param cfg cache configuration
+     */
+    private void saveCacheConfiguration(CacheConfiguration<?, ?> cfg) {
+        if (cctx.pageStore() != null && cctx.database().persistenceEnabled() && !cctx.kernalContext().clientNode()) {
+            try {
+                cctx.pageStore().storeCacheData(
+                    new StoredCacheData(cfg)
+                );
+            }
+            catch (IgniteCheckedException e) {
+                U.error(log(), "Error while saving cache configuration on disk, cfg = " + cfg, e);
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/cdac5a87/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
index a1eb4af..56dcac0 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
@@ -56,9 +56,6 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import javax.management.InstanceNotFoundException;
-import javax.management.JMException;
-import javax.management.MBeanRegistrationException;
 import javax.management.ObjectName;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
@@ -98,6 +95,7 @@ import org.apache.ignite.internal.pagemem.wal.record.delta.PartitionDestroyRecor
 import org.apache.ignite.internal.pagemem.wal.record.delta.PartitionMetaStateRecord;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
+import org.apache.ignite.internal.processors.cache.CacheGroupDescriptor;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
@@ -1453,11 +1451,12 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
         // TODO IGNITE-5075: cache descriptor can be removed.
         GridCacheSharedContext sharedCtx = context();
 
-        String memPlcName = sharedCtx
-            .cache()
-            .cacheGroupDescriptors().get(grpId)
-            .config()
-            .getMemoryPolicyName();
+        CacheGroupDescriptor desc = sharedCtx.cache().cacheGroupDescriptors().get(grpId);
+
+        if (desc == null)
+            throw new IgniteCheckedException("Failed to find cache group descriptor [grpId=" + grpId + ']');
+
+        String memPlcName = desc.config().getMemoryPolicyName();
 
         return (PageMemoryEx)sharedCtx.database().memoryPolicy(memPlcName).pageMemory();
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/cdac5a87/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
index 0041ea6..13bcd2a 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
@@ -210,7 +210,6 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
     @Override public void storeCacheData(
         StoredCacheData cacheData
     ) throws IgniteCheckedException {
-
         File cacheWorkDir = cacheWorkDirectory(cacheData.config());
         File file;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/cdac5a87/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index d44be2c..baafb1e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -504,21 +504,6 @@ public class GridQueryProcessor extends GridProcessorAdapter {
 
                 if (cacheDesc != null && F.eq(cacheDesc.deploymentId(), proposeMsg.deploymentId()))
                     cacheDesc.schemaChangeFinish(msg);
-
-                if (ctx.cache().context().pageStore() != null &&
-                    ctx.cache().context().database().persistenceEnabled()) {
-
-                    StoredCacheData cacheData = new StoredCacheData(cacheDesc.cacheConfiguration());
-
-                    cacheData.queryEntities(cacheDesc.schema().entities());
-
-                    try {
-                        ctx.cache().context().pageStore().storeCacheData(cacheData);
-                    }
-                    catch (IgniteCheckedException e) {
-                        throw new IllegalStateException("Failed to persist cache data: " + cacheData.config().getName(), e);
-                    }
-                }
             }
 
             // Propose message will be used from exchange thread to

http://git-wip-us.apache.org/repos/asf/ignite/blob/cdac5a87/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
index 189b866..5873a35 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsDynamicCacheTest.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.processors.cache.persistence;
 
 import java.io.Serializable;
 import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
@@ -160,6 +161,48 @@ public class IgnitePdsDynamicCacheTest extends IgniteDbDynamicCacheSelfTest {
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testDynamicCacheSavingOnNewNode() throws Exception {
+        Ignite ignite = startGrid(0);
+
+        ignite.active(true);
+
+        CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+        ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
+        ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
+        ccfg.setRebalanceMode(CacheRebalanceMode.SYNC);
+        ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
+
+        IgniteCache cache = ignite.getOrCreateCache(ccfg);
+
+        for (int i = 0; i < 160; i++)
+            cache.put(i, i);
+
+        ignite = startGrid(1);
+
+        awaitPartitionMapExchange();
+
+        cache = ignite.cache(DEFAULT_CACHE_NAME);
+
+        for (int i = 0; i < 160; i++)
+            assertEquals(i, cache.get(i));
+
+        stopAllGrids(true);
+
+        startGrid(0);
+        ignite = startGrid(1);
+
+        ignite.active(true);
+
+        cache = ignite.cache(DEFAULT_CACHE_NAME);
+
+        for (int i = 0; i < 160; i++)
+            assertEquals(i, cache.get(i));
+    }
+
+    /**
      * @throws IgniteCheckedException If failed.
      */
     private void deleteWorkFiles() throws IgniteCheckedException {


[19/29] ignite git commit: Merge branch 'ignite-2.1.3' into ignite-2.1.4

Posted by nt...@apache.org.
Merge branch 'ignite-2.1.3' into ignite-2.1.4


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

Branch: refs/heads/ignite-5947
Commit: 74d6ab9916b3a01c78cdf1ad86211c9fcbb2214d
Parents: 3a7d4f4 2e5c343
Author: Alexey Goncharuk <al...@gmail.com>
Authored: Mon Aug 14 11:08:28 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Mon Aug 14 11:08:28 2017 +0300

----------------------------------------------------------------------
 .../cache/persistence/tree/io/PagePartitionCountersIO.java         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[29/29] ignite git commit: IGNITE-5497 WIP

Posted by nt...@apache.org.
IGNITE-5497 WIP

Signed-off-by: nikolay_tikhonov <nt...@gridgain.com>


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

Branch: refs/heads/ignite-5947
Commit: 49bc7fb414d14e78bd913390a9913b0c79d085fc
Parents: 020ff36
Author: nikolay_tikhonov <nt...@gridgain.com>
Authored: Tue Aug 15 20:51:44 2017 +0300
Committer: nikolay_tikhonov <nt...@gridgain.com>
Committed: Tue Aug 15 20:59:27 2017 +0300

----------------------------------------------------------------------
 .../processors/cache/CacheObjectUtils.java      |  27 +-
 .../cache/CacheTwoDimensionalArrayTest.java     | 291 +++++++++++++++++++
 2 files changed, 316 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/49bc7fb4/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
index f9c76df..6a63768 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import java.lang.reflect.Array;
 import org.apache.ignite.internal.binary.BinaryUtils;
 import org.apache.ignite.internal.util.typedef.F;
 
@@ -123,8 +124,30 @@ public class CacheObjectUtils {
 
         Object[] res = new Object[arr.length];
 
-        for (int i = 0; i < arr.length; i++)
-            res[i] = unwrapBinary(ctx, arr[i], keepBinary, cpy);
+        boolean canCastArray = true;
+        Class cls = null;
+
+        for (int i = 0; i < arr.length; i++) {
+            Object obj = unwrapBinary(ctx, arr[i], keepBinary, cpy);
+
+            res[i] = obj;
+
+            if (canCastArray && obj != null) {
+                if (cls == null)
+                    cls = obj.getClass();
+                else if (cls != obj.getClass())
+                    canCastArray = false;
+            }
+        }
+
+        // If array contains all element the same type then will create typed array.
+        if (canCastArray && cls != null) {
+            Object[] res0 = (Object[])Array.newInstance(cls, res.length);
+
+            System.arraycopy(res, 0, res0, 0, res.length);
+
+            res = res0;
+        }
 
         return res;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/49bc7fb4/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTwoDimensionalArrayTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTwoDimensionalArrayTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTwoDimensionalArrayTest.java
new file mode 100644
index 0000000..69d457c
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheTwoDimensionalArrayTest.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ *
+ */
+public class CacheTwoDimensionalArrayTest extends GridCommonAbstractTest {
+    /** */
+    private static int NODES = 3;
+
+    /** */
+    private static int KEYS = 100;
+
+    /** */
+    private static int size = 5;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGridsMultiThreaded(NODES);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        super.afterTestsStopped();
+
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testSimpleModel() throws Exception {
+        doTestSimpleModel(ATOMIC, PARTITIONED);
+    }
+
+    /**
+     * @param atomicityMode Cache atomicity mode.
+     * @param cacheMode Cache mode.
+     *
+     * @throws Exception If failed.
+     */
+    private void doTestSimpleModel(CacheAtomicityMode atomicityMode, CacheMode cacheMode) throws Exception {
+        CacheConfiguration ccfg = getConfiguration(atomicityMode, cacheMode);
+
+        ignite(0).getOrCreateCache(ccfg);
+
+        int n = size, m = size -1;
+
+        // Primitive empty array.
+        {
+            IgniteCache<Integer, int[][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, new int[n][m]);
+
+            for (int key = 0; key < KEYS; key++) {
+                int[][] exp = new int[n][m];
+
+                int[][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+
+        // Object empty array.
+        {
+            IgniteCache<Integer, Object[][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, new Object[n][m]);
+
+            for (int key = 0; key < KEYS; key++) {
+                Object[][] exp = new Object[n][m];
+
+                Object[][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+
+        {
+            IgniteCache<Integer, int[][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, intArray(n, m, key));
+
+            for (int key = 0; key < KEYS; key++) {
+                int[][] exp = intArray(n, m, key);
+
+                int[][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+
+        {
+            IgniteCache<Integer, int[][][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, new int[5][6][7]);
+
+            for (int key = 0; key < KEYS; key++) {
+                int[][][] exp = new int[5][6][7];
+
+                int[][][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+
+        {
+            IgniteCache<Integer, Object[][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, objectArray(n, m, key));
+
+            for (int key = 0; key < KEYS; key++) {
+                Object[][] exp = objectArray(n, m, key);
+
+                Object[][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+
+        {
+            IgniteCache<Integer, TestObject[][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, testObjectArray(n, m, key));
+
+            for (int key = 0; key < KEYS; key++) {
+                TestObject[][] exp = testObjectArray(n, m, key);
+
+                TestObject[][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+
+        {
+            IgniteCache<Integer, TestObject[][]> cache = ignite(0).cache(ccfg.getName());
+
+            for (int key = 0; key < KEYS; key++)
+                cache.put(key, testObjectArray(n, m, key));
+
+            for (int key = 0; key < KEYS; key++) {
+                TestObject[][] exp = testObjectArray(n, m, key);
+
+                TestObject[][] act = cache.get(key);
+
+                assertArrayEquals(exp, act);
+            }
+
+            cache.removeAll();
+        }
+    }
+
+    /**
+     * @return Array.
+     */
+    private int[][] intArray(int n, int m,int K) {
+        int[][] arr = new int[n][m];
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < m; j++)
+                arr[i][j] = (i + j) * K;
+        }
+
+        return arr;
+    }
+
+    /**
+     * @return Array.
+     */
+    private Object[][] objectArray(int n, int m, int K) {
+        Object[][] arr = new Object[n][m];
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < m; j++)
+                arr[i][j] = ((n + m) % 2 == 0) ? (i + j) * K : new TestObject((i + j) * K);
+        }
+
+        return arr;
+    }
+
+    /**
+     * @return Array.
+     */
+    private TestObject[][] testObjectArray(int n, int m, int K) {
+        TestObject[][] arr = new TestObject[n][m];
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < m; j++)
+                arr[i][j] = new TestObject((i + j) * K);
+        }
+
+        return arr;
+    }
+
+    /**
+     * @param atomicityMode Atomicity mode.
+     * @param cacheMode Cache mode.
+     *
+     * @return Cache configuration.
+     */
+    @NotNull private CacheConfiguration getConfiguration(CacheAtomicityMode atomicityMode,
+        CacheMode cacheMode) {
+        CacheConfiguration<Integer, Integer> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
+
+        ccfg.setCacheMode(cacheMode);
+        ccfg.setAtomicityMode(atomicityMode);
+        ccfg.setWriteSynchronizationMode(FULL_SYNC);
+        ccfg.setBackups(1);
+
+        return ccfg;
+    }
+
+    /**
+     *
+     */
+    private static class TestObject {
+        /** */
+        private int val;
+
+        /**
+         * @param val Value.
+         */
+        public TestObject(int val) {
+            this.val = val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            TestObject object = (TestObject)o;
+
+            return val == object.val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return val;
+        }
+    }
+}


[21/29] ignite git commit: IGNITE-5890 Added estimated time to rebalance completion and time to rebalance start to MXBean - Fixes #2386.

Posted by nt...@apache.org.
IGNITE-5890 Added estimated time to rebalance completion and time to rebalance start to MXBean - Fixes #2386.


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

Branch: refs/heads/ignite-5947
Commit: 13f38d79b57b395e43d42a8f3c278cf48336d7c5
Parents: fde550b
Author: Dmitriy Govorukhin <dm...@gmail.com>
Authored: Mon Aug 14 12:12:46 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Mon Aug 14 14:17:42 2017 +0300

----------------------------------------------------------------------
 .../org/apache/ignite/cache/CacheMetrics.java   |  10 ++
 .../cache/CacheClusterMetricsMXBeanImpl.java    |  10 ++
 .../cache/CacheLocalMetricsMXBeanImpl.java      |  10 ++
 .../processors/cache/CacheMetricsImpl.java      |  36 +++++-
 .../processors/cache/CacheMetricsSnapshot.java  |  18 +++
 .../dht/preloader/GridDhtPartitionDemander.java |  22 +++-
 .../dht/preloader/GridDhtPreloader.java         |  18 +--
 .../cache/CacheGroupsMetricsRebalanceTest.java  | 118 +++++++++++++++++++
 .../platform/PlatformCacheWriteMetricsTask.java |  10 ++
 9 files changed, 234 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
index 0cff4a8..20ea692 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheMetrics.java
@@ -506,6 +506,16 @@ public interface CacheMetrics {
     public long getRebalancingBytesRate();
 
     /**
+     * @return Estimated rebalancing finished time.
+     */
+    public long estimateRebalancingFinishTime();
+
+    /**
+     * @return Rebalancing start time.
+     */
+    public long rebalancingStartTime();
+
+    /**
      * Checks whether statistics collection is enabled in this cache.
      * <p>
      * The default value is {@code false}.

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
index 266c577..df4a6ab 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
@@ -382,4 +382,14 @@ class CacheClusterMetricsMXBeanImpl implements CacheMetricsMXBean {
     @Override public long getRebalancingBytesRate() {
         return cache.clusterMetrics().getRebalancingBytesRate();
     }
+
+    /** {@inheritDoc} */
+    @Override public long estimateRebalancingFinishTime() {
+        return cache.clusterMetrics().estimateRebalancingFinishTime();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long rebalancingStartTime() {
+        return cache.clusterMetrics().rebalancingStartTime();
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
index f363bfe..a767193 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
@@ -382,4 +382,14 @@ class CacheLocalMetricsMXBeanImpl implements CacheMetricsMXBean {
     @Override public long getRebalancingBytesRate() {
         return cache.metrics0().getRebalancingBytesRate();
     }
+
+    /** {@inheritDoc} */
+    @Override public long estimateRebalancingFinishTime() {
+        return cache.metrics0().estimateRebalancingFinishTime();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long rebalancingStartTime() {
+        return cache.metrics0().rebalancingStartTime();
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
index 6a8ae0b..d03a6f8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
@@ -29,6 +29,7 @@ import org.apache.ignite.internal.processors.cache.ratemetrics.HitRateMetrics;
 import org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStore;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
 
 /**
  * Adapter for cache metrics.
@@ -108,6 +109,9 @@ public class CacheMetricsImpl implements CacheMetrics {
     /** Total rebalanced bytes count. */
     private AtomicLong totalRebalancedBytes = new AtomicLong();
 
+    /** Rebalanced start time. */
+    private AtomicLong rebalanceStartTime = new AtomicLong(-1L);
+
     /** Estimated rebalancing keys count. */
     private AtomicLong estimatedRebalancingKeys = new AtomicLong();
 
@@ -734,7 +738,7 @@ public class CacheMetricsImpl implements CacheMetrics {
     }
 
     /** {@inheritDoc} */
-    public int getTotalPartitionsCount() {
+    @Override public int getTotalPartitionsCount() {
         int res = 0;
 
         if (cctx.isLocal())
@@ -749,7 +753,7 @@ public class CacheMetricsImpl implements CacheMetrics {
     }
 
     /** {@inheritDoc} */
-    public int getRebalancingPartitionsCount() {
+    @Override public int getRebalancingPartitionsCount() {
         int res = 0;
 
         if (cctx.isLocal())
@@ -764,17 +768,17 @@ public class CacheMetricsImpl implements CacheMetrics {
     }
 
     /** {@inheritDoc} */
-    public long getKeysToRebalanceLeft() {
+    @Override public long getKeysToRebalanceLeft() {
         return Math.max(0, estimatedRebalancingKeys.get() - rebalancedKeys.get());
     }
 
     /** {@inheritDoc} */
-    public long getRebalancingKeysRate() {
+    @Override public long getRebalancingKeysRate() {
         return rebalancingKeysRate.getRate();
     }
 
     /** {@inheritDoc} */
-    public long getRebalancingBytesRate() {
+    @Override public long getRebalancingBytesRate() {
         return rebalancingBytesRate.getRate();
     }
 
@@ -791,6 +795,28 @@ public class CacheMetricsImpl implements CacheMetrics {
         rebalancingBytesRate.clear();
 
         rebalancingKeysRate.clear();
+
+        rebalanceStartTime.set(-1L);
+    }
+
+    /**
+     *
+     */
+    public void startRebalance(long delay){
+        rebalanceStartTime.addAndGet(delay + U.currentTimeMillis());
+    }
+
+    /** {@inheritDoc} */
+    @Override public long estimateRebalancingFinishTime() {
+        long rate = rebalancingKeysRate.getRate();
+
+        return rate <= 0 ? -1L :
+            ((getKeysToRebalanceLeft() / rate) * REBALANCE_RATE_INTERVAL) + U.currentTimeMillis();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long rebalancingStartTime() {
+        return rebalanceStartTime.get();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsSnapshot.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsSnapshot.java
index e9141c6..2d38db8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsSnapshot.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsSnapshot.java
@@ -203,6 +203,12 @@ public class CacheMetricsSnapshot implements CacheMetrics, Externalizable {
     /** Get rebalancing bytes rate. */
     private long rebalancingBytesRate;
 
+    /** Start rebalance time. */
+    private long rebalanceStartTime;
+
+    /** Estimate rebalance finish time. */
+    private long rebalanceFinishTime;
+
     /** */
     private String keyType;
 
@@ -307,6 +313,8 @@ public class CacheMetricsSnapshot implements CacheMetrics, Externalizable {
         keysToRebalanceLeft = m.getKeysToRebalanceLeft();
         rebalancingBytesRate = m.getRebalancingBytesRate();
         rebalancingKeysRate = m.getRebalancingKeysRate();
+        rebalanceStartTime = m.rebalancingStartTime();
+        rebalanceFinishTime = m.estimateRebalancingFinishTime();
     }
 
     /**
@@ -716,6 +724,16 @@ public class CacheMetricsSnapshot implements CacheMetrics, Externalizable {
     }
 
     /** {@inheritDoc} */
+    @Override public long estimateRebalancingFinishTime() {
+        return rebalanceFinishTime;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long rebalancingStartTime() {
+        return rebalanceStartTime;
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean isWriteBehindEnabled() {
         return isWriteBehindEnabled;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
index 248b739..2258187 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
@@ -257,11 +257,13 @@ public class GridDhtPartitionDemander {
      * @param forcedRebFut External future for forced rebalance.
      * @return Rebalancing runnable.
      */
-    Runnable addAssignments(final GridDhtPreloaderAssignments assigns,
+    Runnable addAssignments(
+        final GridDhtPreloaderAssignments assigns,
         boolean force,
         int cnt,
         final Runnable next,
-        @Nullable final GridCompoundFuture<Boolean, Boolean> forcedRebFut) {
+        @Nullable final GridCompoundFuture<Boolean, Boolean> forcedRebFut
+    ) {
         if (log.isDebugEnabled())
             log.debug("Adding partition assignments: " + assigns);
 
@@ -289,14 +291,14 @@ public class GridDhtPartitionDemander {
 
             rebalanceFut = fut;
 
-            fut.sendRebalanceStartedEvent();
-
-            for (GridCacheContext cctx : grp.caches()) {
+            for (final GridCacheContext cctx : grp.caches()) {
                 if (cctx.config().isStatisticsEnabled()) {
                     final CacheMetricsImpl metrics = cctx.cache().metrics0();
 
                     metrics.clearRebalanceCounters();
 
+                    metrics.startRebalance(0);
+
                     rebalanceFut.listen(new IgniteInClosure<IgniteInternalFuture<Boolean>>() {
                         @Override public void apply(IgniteInternalFuture<Boolean> fut) {
                             metrics.clearRebalanceCounters();
@@ -305,6 +307,8 @@ public class GridDhtPartitionDemander {
                 }
             }
 
+            fut.sendRebalanceStartedEvent();
+
             if (assigns.cancelled()) { // Pending exchange.
                 if (log.isDebugEnabled())
                     log.debug("Rebalancing skipped due to cancelled assignments.");
@@ -350,6 +354,14 @@ public class GridDhtPartitionDemander {
             };
         }
         else if (delay > 0) {
+            for (GridCacheContext cctx : grp.caches()) {
+                if (cctx.config().isStatisticsEnabled()) {
+                    final CacheMetricsImpl metrics = cctx.cache().metrics0();
+
+                    metrics.startRebalance(delay);
+                }
+            }
+
             GridTimeoutObject obj = lastTimeoutObj.get();
 
             if (obj != null)

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
index 7efd4aa..305da92 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPreloader.java
@@ -306,12 +306,12 @@ public class GridDhtPreloader extends GridCachePreloaderAdapter {
 
                         GridDhtPartitionDemandMessage msg = assigns.get(n);
 
-                    if (msg == null) {
-                        assigns.put(n, msg = new GridDhtPartitionDemandMessage(
-                            top.updateSequence(),
-                            exchId.topologyVersion(),
-                            grp.groupId()));
-                    }
+                        if (msg == null) {
+                            assigns.put(n, msg = new GridDhtPartitionDemandMessage(
+                                top.updateSequence(),
+                                exchId.topologyVersion(),
+                                grp.groupId()));
+                        }
 
                         msg.addPartition(p, false);
                     }
@@ -396,11 +396,13 @@ public class GridDhtPreloader extends GridCachePreloaderAdapter {
     }
 
     /** {@inheritDoc} */
-    @Override public Runnable addAssignments(GridDhtPreloaderAssignments assignments,
+    @Override public Runnable addAssignments(
+        GridDhtPreloaderAssignments assignments,
         boolean forceRebalance,
         int cnt,
         Runnable next,
-        @Nullable GridCompoundFuture<Boolean, Boolean> forcedRebFut) {
+        @Nullable GridCompoundFuture<Boolean, Boolean> forcedRebFut
+    ) {
         return demander.addAssignments(assignments, forceRebalance, cnt, next, forcedRebFut);
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupsMetricsRebalanceTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupsMetricsRebalanceTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupsMetricsRebalanceTest.java
index c15fa5f..a1a855a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupsMetricsRebalanceTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGroupsMetricsRebalanceTest.java
@@ -21,20 +21,28 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteDataStreamer;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMetrics;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CacheRebalanceMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.events.CacheRebalancingEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
+import org.apache.ignite.internal.util.typedef.PA;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
 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.testframework.junits.common.GridCommonAbstractTest;
 
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_REBALANCE_STATISTICS_TIME_INTERVAL;
+import static org.apache.ignite.testframework.GridTestUtils.runAsync;
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
+
 /**
  *
  */
@@ -71,6 +79,7 @@ public class CacheGroupsMetricsRebalanceTest extends GridCommonAbstractTest {
             .setCacheMode(CacheMode.PARTITIONED)
             .setAtomicityMode(CacheAtomicityMode.ATOMIC)
             .setRebalanceMode(CacheRebalanceMode.ASYNC)
+            .setRebalanceBatchSize(100)
             .setStatisticsEnabled(true);
 
         CacheConfiguration cfg2 = new CacheConfiguration(cfg1)
@@ -137,4 +146,113 @@ public class CacheGroupsMetricsRebalanceTest extends GridCommonAbstractTest {
 
         assertTrue(ratio > 40 && ratio < 60);
     }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testRebalanceEstimateFinishTime() throws Exception {
+        System.setProperty(IGNITE_REBALANCE_STATISTICS_TIME_INTERVAL, String.valueOf(1000));
+
+        Ignite ig1 = startGrid(1);
+
+        final int KEYS = 4_000_000;
+
+        IgniteCache<Object, Object> cache1 = ig1.cache(CACHE1);
+
+        try (IgniteDataStreamer<Integer, String> st = ig1.dataStreamer(CACHE1)) {
+            for (int i = 0; i < KEYS; i++)
+                st.addData(i, CACHE1 + "-" + i);
+        }
+
+        final CountDownLatch finishRebalanceLatch = new CountDownLatch(1);
+
+        final Ignite ig2 = startGrid(2);
+
+        ig2.events().localListen(new IgnitePredicate<Event>() {
+            @Override public boolean apply(Event evt) {
+                CacheRebalancingEvent rebEvent = (CacheRebalancingEvent)evt;
+
+                if (rebEvent.cacheName().equals(CACHE1)) {
+                    System.out.println("CountDown rebalance stop latch:" + rebEvent.cacheName());
+
+                    finishRebalanceLatch.countDown();
+                }
+
+                return false;
+            }
+        }, EventType.EVT_CACHE_REBALANCE_STOPPED);
+
+        waitForCondition(new PA() {
+            @Override public boolean apply() {
+                return ig2.cache(CACHE1).localMetrics().rebalancingStartTime() != -1L;
+            }
+        }, 5_000);
+
+        CacheMetrics metrics = ig2.cache(CACHE1).localMetrics();
+
+        long startTime = metrics.rebalancingStartTime();
+
+        assertTrue(startTime > 0);
+        assertTrue((U.currentTimeMillis() - startTime) < 5000);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        runAsync(new Runnable() {
+            @Override public void run() {
+                // Waiting 25% keys will be rebalanced.
+                int partKeys = KEYS / 2;
+
+                final long keysLine = (long)(partKeys - (partKeys * 0.25));
+
+                System.out.println("Wait until keys left will be less " + keysLine);
+
+                while (finishRebalanceLatch.getCount() != 0) {
+                    CacheMetrics m = ig2.cache(CACHE1).localMetrics();
+
+                    long keyLeft = m.getKeysToRebalanceLeft();
+
+                    if (keyLeft > 0 && keyLeft < keysLine)
+                        latch.countDown();
+
+                    System.out.println("Keys left: " + m.getKeysToRebalanceLeft());
+
+                    try {
+                        Thread.sleep(1_000);
+                    }
+                    catch (InterruptedException e) {
+                        System.out.println("Interrupt thread: " + e.getMessage());
+
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        });
+
+        latch.await();
+
+        long finishTime = ig2.cache(CACHE1).localMetrics().estimateRebalancingFinishTime();
+
+        assertTrue(finishTime > 0);
+
+        long timePassed = U.currentTimeMillis() - startTime;
+        long timeLeft = finishTime - System.currentTimeMillis();
+
+        assertTrue(finishRebalanceLatch.await(timeLeft + 2_000, TimeUnit.SECONDS));
+
+        System.out.println(
+            "TimePassed:" + timePassed +
+                "\nTimeLeft:" + timeLeft +
+                "\nTime to rebalance: " + (finishTime - startTime) +
+                "\nStartTime: " + startTime +
+                "\nFinishTime: " + finishTime
+        );
+
+        System.clearProperty(IGNITE_REBALANCE_STATISTICS_TIME_INTERVAL);
+
+        System.out.println("Rebalance time:" + (U.currentTimeMillis() - startTime));
+
+        long diff = finishTime - U.currentTimeMillis();
+
+        assertTrue("Expected less 5000, Actual:" + diff, Math.abs(diff) < 10_000);
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/13f38d79/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheWriteMetricsTask.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheWriteMetricsTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheWriteMetricsTask.java
index f1d8114..64ff0bc 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheWriteMetricsTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformCacheWriteMetricsTask.java
@@ -433,6 +433,16 @@ public class PlatformCacheWriteMetricsTask extends ComputeTaskAdapter<Long, Obje
         @Override public long getHeapEntriesCount() {
             return 59;
         }
+
+        /** {@inheritDoc} */
+        @Override public long estimateRebalancingFinishTime() {
+            return 60;
+        }
+
+        /** {@inheritDoc} */
+        @Override public long rebalancingStartTime() {
+            return 61;
+        }
     }
 }
 


[03/29] ignite git commit: ignite-5712 Context switching for optimistic transactions

Posted by nt...@apache.org.
ignite-5712 Context switching for optimistic transactions


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

Branch: refs/heads/ignite-5947
Commit: e255a564985a12113984ec02f15a4443495b8ffc
Parents: 3fdf453
Author: Nikolay Izhikov <ni...@gmail.com>
Authored: Wed Aug 2 11:52:44 2017 +0300
Committer: sboikov <sb...@gridgain.com>
Committed: Wed Aug 2 18:55:36 2017 +0300

----------------------------------------------------------------------
 .../ignite/tests/utils/TestTransaction.java     |  10 +
 .../cache/GridCacheSharedContext.java           |  24 +
 .../cache/distributed/near/GridNearTxLocal.java |  51 ++
 .../store/GridCacheStoreManagerAdapter.java     |  10 +
 .../cache/transactions/IgniteTxAdapter.java     |  20 +-
 .../cache/transactions/IgniteTxManager.java     |  74 ++
 .../cache/transactions/IgniteTxMap.java         |   2 +-
 .../transactions/TransactionProxyImpl.java      |  46 +-
 .../apache/ignite/transactions/Transaction.java |  14 +
 .../ignite/transactions/TransactionState.java   |   7 +-
 ...ptimisticTxSuspendResumeMultiServerTest.java |  30 +
 .../IgniteOptimisticTxSuspendResumeTest.java    | 751 +++++++++++++++++++
 .../IgnitePessimisticTxSuspendResumeTest.java   |  91 +++
 .../ignite/testframework/GridTestUtils.java     |  26 +
 .../cache/GridAbstractCacheStoreSelfTest.java   |  10 +
 .../testsuites/IgniteCacheTestSuite6.java       |  42 ++
 .../processors/cache/jta/CacheJtaManager.java   |   5 +-
 .../processors/cache/jta/CacheJtaResource.java  |  28 +-
 .../GridJtaTransactionManagerSelfTest.java      | 208 +++++
 .../ignite/testsuites/IgniteJtaTestSuite.java   |   5 +-
 20 files changed, 1438 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
----------------------------------------------------------------------
diff --git a/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java b/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
index 4a03d25..e587bd7 100644
--- a/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
+++ b/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
@@ -140,4 +140,14 @@ public class TestTransaction implements Transaction {
     @Override public IgniteFuture<Void> rollbackAsync() throws IgniteException {
         return null;
     }
+
+    /** {@inheritDoc} */
+    @Override public void suspend() throws IgniteException{
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void resume() throws IgniteException {
+        // No-op.
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
index 5387cc8..3fb63dc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
@@ -944,6 +944,30 @@ public class GridCacheSharedContext<K, V> {
     }
 
     /**
+     * Suspends transaction. It could be resume later. Supported only for optimistic transactions.
+     *
+     * @param tx Transaction to suspend.
+     * @throws IgniteCheckedException If suspension failed.
+     */
+    public void suspendTx(GridNearTxLocal tx) throws IgniteCheckedException {
+        tx.txState().awaitLastFut(this);
+
+        tx.suspend();
+    }
+
+    /**
+     * Resume transaction if it was previously suspended.
+     *
+     * @param tx Transaction to resume.
+     * @throws IgniteCheckedException If resume failed.
+     */
+    public void resumeTx(GridNearTxLocal tx) throws IgniteCheckedException {
+        tx.txState().awaitLastFut(this);
+
+        tx.resume();
+    }
+
+    /**
      * @return Store session listeners.
      */
     @Nullable public Collection<CacheStoreSessionListener> storeSessionListeners() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
index 81e5ca8..2fb0ff3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
@@ -105,12 +105,14 @@ import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRA
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE;
 import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry.SER_READ_EMPTY_ENTRY_VER;
 import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry.SER_READ_NOT_EMPTY_VER;
+import static org.apache.ignite.transactions.TransactionState.ACTIVE;
 import static org.apache.ignite.transactions.TransactionState.COMMITTED;
 import static org.apache.ignite.transactions.TransactionState.COMMITTING;
 import static org.apache.ignite.transactions.TransactionState.PREPARED;
 import static org.apache.ignite.transactions.TransactionState.PREPARING;
 import static org.apache.ignite.transactions.TransactionState.ROLLED_BACK;
 import static org.apache.ignite.transactions.TransactionState.ROLLING_BACK;
+import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
 import static org.apache.ignite.transactions.TransactionState.UNKNOWN;
 
 /**
@@ -2851,6 +2853,47 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements AutoClosea
     }
 
     /**
+     * Suspends transaction. It could be resumed later. Supported only for optimistic transactions.
+     *
+     * @throws IgniteCheckedException If the transaction is in an incorrect state, or timed out.
+     */
+    public void suspend() throws IgniteCheckedException {
+        if (log.isDebugEnabled())
+            log.debug("Suspend near local tx: " + this);
+
+        if (pessimistic())
+            throw new UnsupportedOperationException("Suspension is not supported for pessimistic transactions.");
+
+        if (threadId() != Thread.currentThread().getId())
+            throw new IgniteCheckedException("Only thread started transaction can suspend it.");
+
+        synchronized (this) {
+            checkValid();
+
+            cctx.tm().suspendTx(this);
+        }
+    }
+
+    /**
+     * Resumes transaction (possibly in another thread) if it was previously suspended.
+     *
+     * @throws IgniteCheckedException If the transaction is in an incorrect state, or timed out.
+     */
+    public void resume() throws IgniteCheckedException {
+        if (log.isDebugEnabled())
+            log.debug("Resume near local tx: " + this);
+
+        if (pessimistic())
+            throw new UnsupportedOperationException("Resume is not supported for pessimistic transactions.");
+
+        synchronized (this) {
+            checkValid();
+
+            cctx.tm().resumeTx(this);
+        }
+    }
+
+    /**
      * @param maps Mappings.
      */
     void addEntryMapping(@Nullable Collection<GridDistributedTxMapping> maps) {
@@ -3952,6 +3995,14 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements AutoClosea
     }
 
     /**
+     * @param threadId new owner of transaction.
+     * @throws IgniteCheckedException if method executed not in the middle of resume or suspend.
+     */
+    public void threadId(long threadId) {
+        this.threadId = threadId;
+    }
+
+    /**
      * Post-lock closure.
      *
      * @param <T> Return type.

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
index c02e2c7..bb16ad1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
@@ -1358,6 +1358,11 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
         }
 
         /** {@inheritDoc} */
+        @Override public void suspend() throws IgniteException {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
         @Override public long timeout() {
             return tx.timeout();
         }
@@ -1403,6 +1408,11 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
         }
 
         /** {@inheritDoc} */
+        @Override public void resume() throws IgniteException {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
         @Override public IgniteAsyncSupport withAsync() {
             throw new UnsupportedOperationException();
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
index 91ce3ce..61ca78c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
@@ -97,6 +97,7 @@ import static org.apache.ignite.transactions.TransactionState.PREPARED;
 import static org.apache.ignite.transactions.TransactionState.PREPARING;
 import static org.apache.ignite.transactions.TransactionState.ROLLED_BACK;
 import static org.apache.ignite.transactions.TransactionState.ROLLING_BACK;
+import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
 
 /**
  * Managed transaction adapter.
@@ -977,10 +978,10 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
 
             switch (state) {
                 case ACTIVE: {
-                    valid = false;
+                    valid = prev == SUSPENDED;
 
                     break;
-                } // Active is initial state and cannot be transitioned to.
+                }
                 case PREPARING: {
                     valid = prev == ACTIVE;
 
@@ -1025,15 +1026,20 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
                 }
 
                 case MARKED_ROLLBACK: {
-                    valid = prev == ACTIVE || prev == PREPARING || prev == PREPARED;
+                    valid = prev == ACTIVE || prev == PREPARING || prev == PREPARED || prev == SUSPENDED;
 
                     break;
                 }
 
                 case ROLLING_BACK: {
-                    valid =
-                        prev == ACTIVE || prev == MARKED_ROLLBACK || prev == PREPARING ||
-                            prev == PREPARED || (prev == COMMITTING && local() && !dht());
+                    valid = prev == ACTIVE || prev == MARKED_ROLLBACK || prev == PREPARING ||
+                        prev == PREPARED || prev == SUSPENDED || (prev == COMMITTING && local() && !dht());
+
+                    break;
+                }
+
+                case SUSPENDED: {
+                    valid = prev == ACTIVE;
 
                     break;
                 }
@@ -1064,7 +1070,7 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
 
         if (valid) {
             // Seal transactions maps.
-            if (state != ACTIVE)
+            if (state != ACTIVE && state != SUSPENDED)
                 seal();
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
index 7d612ec..a427da3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
@@ -113,6 +113,7 @@ import static org.apache.ignite.transactions.TransactionState.COMMITTING;
 import static org.apache.ignite.transactions.TransactionState.MARKED_ROLLBACK;
 import static org.apache.ignite.transactions.TransactionState.PREPARED;
 import static org.apache.ignite.transactions.TransactionState.PREPARING;
+import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
 import static org.apache.ignite.transactions.TransactionState.UNKNOWN;
 import static org.jsr166.ConcurrentLinkedHashMap.QueuePolicy.PER_SEGMENT_Q;
 
@@ -2240,6 +2241,79 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
     }
 
     /**
+     * Suspends transaction.
+     * Should not be used directly. Use tx.suspend() instead.
+     *
+     * @param tx Transaction to be suspended.
+     *
+     * @see #resumeTx(GridNearTxLocal)
+     * @see GridNearTxLocal#suspend()
+     * @see GridNearTxLocal#resume()
+     */
+    public void suspendTx(final GridNearTxLocal tx) throws IgniteCheckedException {
+        assert tx != null && !tx.system() : tx;
+
+        if (!tx.state(SUSPENDED)) {
+            throw new IgniteCheckedException("Trying to suspend transaction with incorrect state "
+                + "[expected=" + ACTIVE + ", actual=" + tx.state() + ']');
+        }
+
+        clearThreadMap(tx);
+
+        transactionMap(tx).remove(tx.xidVersion(), tx);
+    }
+
+    /**
+     * Resume transaction in current thread.
+     * Please don't use directly. Use tx.resume() instead.
+     *
+     * @param tx Transaction to be resumed.
+     *
+     * @see #suspendTx(GridNearTxLocal)
+     * @see GridNearTxLocal#suspend()
+     * @see GridNearTxLocal#resume()
+     */
+    public void resumeTx(GridNearTxLocal tx) throws IgniteCheckedException {
+        assert tx != null && !tx.system() : tx;
+        assert !threadMap.containsValue(tx) : tx;
+        assert !transactionMap(tx).containsValue(tx) : tx;
+        assert !haveSystemTxForThread(Thread.currentThread().getId());
+
+        if(!tx.state(ACTIVE)) {
+            throw new IgniteCheckedException("Trying to resume transaction with incorrect state "
+                + "[expected=" + SUSPENDED + ", actual=" + tx.state() + ']');
+        }
+
+        long threadId = Thread.currentThread().getId();
+
+        if (threadMap.putIfAbsent(threadId, tx) != null)
+            throw new IgniteCheckedException("Thread already start a transaction.");
+
+        if (transactionMap(tx).putIfAbsent(tx.xidVersion(), tx) != null)
+            throw new IgniteCheckedException("Thread already start a transaction.");
+
+        tx.threadId(threadId);
+    }
+
+    /**
+     * @param threadId Thread id.
+     * @return True if thread have system transaction. False otherwise.
+     */
+    private boolean haveSystemTxForThread(long threadId) {
+        if (!sysThreadMap.isEmpty()) {
+            for (GridCacheContext cacheCtx : cctx.cache().context().cacheContexts()) {
+                if (!cacheCtx.systemTx())
+                    continue;
+
+                if (sysThreadMap.containsKey(new TxThreadKey(threadId, cacheCtx.cacheId())))
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Timeout object for node failure handler.
      */
     private final class NodeFailureTimeoutObject extends GridTimeoutObjectAdapter {

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxMap.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxMap.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxMap.java
index 429c995..6b79550 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxMap.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxMap.java
@@ -190,4 +190,4 @@ public class IgniteTxMap extends AbstractMap<IgniteTxKey, IgniteTxEntry> impleme
     @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
         throw new IllegalStateException("Transaction view map should never be serialized: " + this);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
index 8750cab..f25fc36 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
@@ -44,6 +44,8 @@ import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 import org.apache.ignite.transactions.TransactionState;
 
+import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
+
 /**
  * Cache transaction proxy.
  */
@@ -98,6 +100,18 @@ public class TransactionProxyImpl<K, V> implements TransactionProxy, Externaliza
      * Enters a call.
      */
     private void enter() {
+        enter(false);
+    }
+
+    /**
+     * Enters a call.
+     *
+     * @param resume Flag to indicate that resume operation in progress.
+     */
+    private void enter(boolean resume) {
+        if (!resume && state() == SUSPENDED)
+            throw new IgniteException("Tx in SUSPENDED state. All operations except resume are prohibited.");
+
         if (cctx.deploymentEnabled())
             cctx.deploy().onEnter();
 
@@ -204,6 +218,21 @@ public class TransactionProxyImpl<K, V> implements TransactionProxy, Externaliza
     }
 
     /** {@inheritDoc} */
+    @Override public void suspend() throws IgniteException {
+        enter();
+
+        try {
+            cctx.suspendTx(tx);
+        }
+        catch (IgniteCheckedException e) {
+            throw U.convertException(e);
+        }
+        finally {
+            leave();
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public long timeout(long timeout) {
         return tx.timeout(timeout);
     }
@@ -333,6 +362,21 @@ public class TransactionProxyImpl<K, V> implements TransactionProxy, Externaliza
         }
     }
 
+    /** {@inheritDoc} */
+    @Override public void resume() throws IgniteException {
+        enter(true);
+
+        try {
+            cctx.resumeTx(tx);
+        }
+        catch (IgniteCheckedException e) {
+            throw U.convertException(e);
+        }
+        finally {
+            leave();
+        }
+    }
+
     /**
      * @param res Result to convert to finished future.
      */
@@ -377,4 +421,4 @@ public class TransactionProxyImpl<K, V> implements TransactionProxy, Externaliza
     @Override public String toString() {
         return S.toString(TransactionProxyImpl.class, this);
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java b/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
index 57a2b00..a1b4d78 100644
--- a/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
+++ b/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
@@ -272,4 +272,18 @@ public interface Transaction extends AutoCloseable, IgniteAsyncSupport {
      * @throws IgniteException If rollback failed.
      */
     public IgniteFuture<Void> rollbackAsync() throws IgniteException;
+
+    /**
+     * Resume transaction if it was previously suspended. <strong>Supported only for optimistic transactions.</strong>
+     *
+     * @throws IgniteException If resume failed.
+     */
+    public void resume() throws IgniteException;
+
+    /**
+     * Suspends transaction. It could be resumed later. <strong>Supported only for optimistic transactions.</strong>
+     *
+     * @throws IgniteException If suspension failed.
+     */
+    public void suspend() throws IgniteException;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/main/java/org/apache/ignite/transactions/TransactionState.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/transactions/TransactionState.java b/modules/core/src/main/java/org/apache/ignite/transactions/TransactionState.java
index 1980242..d01c0fa 100644
--- a/modules/core/src/main/java/org/apache/ignite/transactions/TransactionState.java
+++ b/modules/core/src/main/java/org/apache/ignite/transactions/TransactionState.java
@@ -48,7 +48,10 @@ public enum TransactionState {
     ROLLED_BACK,
 
     /** Transaction rollback failed or is otherwise unknown state. */
-    UNKNOWN;
+    UNKNOWN,
+
+    /** Transaction has been suspended by user. */
+    SUSPENDED;
 
     /** Enumerated values. */
     private static final TransactionState[] VALS = values();
@@ -62,4 +65,4 @@ public enum TransactionState {
     @Nullable public static TransactionState fromOrdinal(int ord) {
         return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeMultiServerTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeMultiServerTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeMultiServerTest.java
new file mode 100644
index 0000000..a6318d4
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeMultiServerTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ *
+ */
+public class IgniteOptimisticTxSuspendResumeMultiServerTest extends IgniteOptimisticTxSuspendResumeTest {
+    /**
+     * @return Number of server nodes.
+     */
+    protected int serversNumber() {
+        return 4;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java
new file mode 100644
index 0000000..d16aebd
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteOptimisticTxSuspendResumeTest.java
@@ -0,0 +1,751 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.CI1;
+import org.apache.ignite.internal.util.typedef.CI2;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionIsolation;
+import org.apache.ignite.transactions.TransactionTimeoutException;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
+import static org.apache.ignite.transactions.TransactionState.ACTIVE;
+import static org.apache.ignite.transactions.TransactionState.COMMITTED;
+import static org.apache.ignite.transactions.TransactionState.MARKED_ROLLBACK;
+import static org.apache.ignite.transactions.TransactionState.ROLLED_BACK;
+import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
+
+/**
+ *
+ */
+public class IgniteOptimisticTxSuspendResumeTest extends GridCommonAbstractTest {
+    /** Transaction timeout. */
+    private static final long TX_TIMEOUT = 100;
+
+    /** Future timeout */
+    private static final int FUT_TIMEOUT = 5000;
+
+    private boolean client = false;
+
+    /**
+     * List of closures to execute transaction operation that prohibited in suspended state.
+     */
+    private static final List<CI1Exc<Transaction>> SUSPENDED_TX_PROHIBITED_OPS = Arrays.asList(
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.suspend();
+            }
+        },
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.close();
+            }
+        },
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.commit();
+            }
+        },
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.commitAsync().get(FUT_TIMEOUT);
+            }
+        },
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.rollback();
+            }
+        },
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.rollbackAsync().get(FUT_TIMEOUT);
+            }
+        },
+        new CI1Exc<Transaction>() {
+            @Override public void applyx(Transaction tx) throws Exception {
+                tx.setRollbackOnly();
+            }
+        }
+    );
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setClientMode(client);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGrids(serversNumber());
+
+        if (serversNumber() > 1) {
+            client = true;
+
+            startGrid(serversNumber());
+
+            startGrid(serversNumber() + 1);
+
+            client = false;
+        }
+
+        awaitPartitionMapExchange();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        super.afterTestsStopped();
+
+        stopAllGrids(true);
+    }
+
+    /**
+     * @return Number of server nodes.
+     */
+    protected int serversNumber() {
+        return 1;
+    }
+
+    /**
+     * Test for transaction starting in one thread, continuing in another.
+     *
+     * @throws Exception If failed.
+     */
+    public void testResumeTxInAnotherThread() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    final Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                    final AtomicInteger cntr = new AtomicInteger(0);
+
+                    cache.put(-1, -1);
+                    cache.put(cntr.get(), cntr.getAndIncrement());
+
+                    tx.suspend();
+
+                    assertEquals(SUSPENDED, tx.state());
+
+                    assertNull("Thread already have tx", ignite.transactions().tx());
+
+                    assertNull(cache.get(-1));
+                    assertNull(cache.get(cntr.get()));
+
+                    for (int i = 0; i < 10; i++) {
+                        GridTestUtils.runAsync(new Runnable() {
+                            @Override public void run() {
+                                assertEquals(SUSPENDED, tx.state());
+
+                                tx.resume();
+
+                                assertEquals(ACTIVE, tx.state());
+
+                                cache.put(cntr.get(), cntr.getAndIncrement());
+
+                                tx.suspend();
+                            }
+                        }).get(FUT_TIMEOUT);
+                    }
+
+                    tx.resume();
+
+                    cache.remove(-1);
+
+                    tx.commit();
+
+                    assertEquals(COMMITTED, tx.state());
+
+                    for (int i = 0; i < cntr.get(); i++)
+                        assertEquals(i, (int)cache.get(i));
+
+                    assertFalse(cache.containsKey(-1));
+
+                    cache.removeAll();
+                }
+            }
+        });
+    }
+
+    /**
+     * Test for transaction starting in one thread, continuing in another, and resuming in initiating thread.
+     * Cache operations performed for a couple of caches.
+     *
+     * @throws Exception If failed.
+     */
+    public void testCrossCacheTxInAnotherThread() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    final IgniteCache<Integer, Integer> otherCache =
+                        ignite.getOrCreateCache(cacheConfiguration(PARTITIONED, 0, false).setName("otherCache"));
+
+                    final Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                    final AtomicInteger cntr = new AtomicInteger(0);
+
+                    cache.put(-1, -1);
+                    otherCache.put(-1, -1);
+
+                    tx.suspend();
+
+                    for (int i = 0; i < 10; i++) {
+                        GridTestUtils.runAsync(new Runnable() {
+                            @Override public void run() {
+                                tx.resume();
+
+                                assertEquals(ACTIVE, tx.state());
+
+                                cache.put(cntr.get(), cntr.get());
+                                otherCache.put(cntr.get(), cntr.getAndIncrement());
+
+                                tx.suspend();
+                            }
+                        }).get(FUT_TIMEOUT);
+                    }
+
+                    tx.resume();
+
+                    cache.remove(-1);
+                    otherCache.remove(-1);
+
+                    tx.commit();
+
+                    assertEquals(COMMITTED, tx.state());
+
+                    for (int i = 0; i < cntr.get(); i++) {
+                        assertEquals(i, (int)cache.get(i));
+                        assertEquals(i, (int)otherCache.get(i));
+                    }
+
+                    assertFalse(cache.containsKey(-1));
+                    assertFalse(otherCache.containsKey(-1));
+
+                    cache.removeAll();
+                    otherCache.removeAll();
+                }
+            }
+        });
+    }
+
+    /**
+     * Test for transaction rollback.
+     *
+     * @throws Exception If failed.
+     */
+    public void testTxRollback() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    final Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                    cache.put(1, 1);
+                    cache.put(2, 2);
+
+                    tx.suspend();
+
+                    assertNull("There is no transaction for current thread", ignite.transactions().tx());
+
+                    assertEquals(SUSPENDED, tx.state());
+
+                    GridTestUtils.runAsync(new Runnable() {
+                        @Override public void run() {
+                            tx.resume();
+
+                            assertEquals(ACTIVE, tx.state());
+
+                            cache.put(3, 3);
+
+                            tx.rollback();
+                        }
+                    }).get(FUT_TIMEOUT);
+
+                    assertEquals(ROLLED_BACK, tx.state());
+
+                    assertFalse(cache.containsKey(1));
+                    assertFalse(cache.containsKey(2));
+                    assertFalse(cache.containsKey(3));
+
+                    cache.removeAll();
+                }
+            }
+        });
+    }
+
+    /**
+     * Test for starting and suspending transactions, and then resuming and committing in another thread.
+     *
+     * @throws Exception If failed.
+     */
+    public void testMultiTxSuspendResume() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    final List<Transaction> clientTxs = new ArrayList<>();
+
+                    for (int i = 0; i < 10; i++) {
+                        Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                        cache.put(i, i);
+
+                        tx.suspend();
+
+                        clientTxs.add(tx);
+                    }
+
+                    GridTestUtils.runMultiThreaded(new CI1Exc<Integer>() {
+                        public void applyx(Integer idx) throws Exception {
+                            Transaction tx = clientTxs.get(idx);
+
+                            assertEquals(SUSPENDED, tx.state());
+
+                            tx.resume();
+
+                            assertEquals(ACTIVE, tx.state());
+
+                            tx.commit();
+                        }
+                    }, 10, "th-suspend");
+
+                    for (int i = 0; i < 10; i++)
+                        assertEquals(i, (int)cache.get(i));
+
+                    cache.removeAll();
+                }
+            }
+        });
+    }
+
+    /**
+     * Test checking all operations(exception resume) on suspended transaction from the other thread are prohibited.
+     *
+     * @throws Exception If failed.
+     */
+    public void testOpsProhibitedOnSuspendedTxFromOtherThread() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (final CI1Exc<Transaction> txOperation : SUSPENDED_TX_PROHIBITED_OPS) {
+                    for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                        final Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                        cache.put(1, 1);
+
+                        tx.suspend();
+
+                        multithreaded(new RunnableX() {
+                            @Override public void runx() throws Exception {
+                                GridTestUtils.assertThrowsWithCause(txOperation, tx, IgniteException.class);
+                            }
+                        }, 1);
+
+                        tx.resume();
+                        tx.close();
+
+                        assertNull(cache.get(1));
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Test checking all operations(exception resume) on suspended transaction are prohibited.
+     *
+     * @throws Exception If failed.
+     */
+    public void testOpsProhibitedOnSuspendedTx() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (CI1Exc<Transaction> txOperation : SUSPENDED_TX_PROHIBITED_OPS) {
+                    for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                        Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                        cache.put(1, 1);
+
+                        tx.suspend();
+
+                        GridTestUtils.assertThrowsWithCause(txOperation, tx, IgniteException.class);
+
+                        tx.resume();
+                        tx.close();
+
+                        assertNull(cache.get(1));
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Test checking timeout on resumed transaction.
+     *
+     * @throws Exception If failed.
+     */
+    public void testTxTimeoutOnResumed() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    final Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation, TX_TIMEOUT, 0);
+
+                    cache.put(1, 1);
+
+                    tx.suspend();
+
+                    Thread.sleep(TX_TIMEOUT * 2);
+
+                    GridTestUtils.assertThrowsWithCause(new Callable<Object>() {
+                        @Override public Object call() throws Exception {
+                            tx.resume();
+
+                            return null;
+                        }
+                    }, TransactionTimeoutException.class);
+
+                    assertEquals(MARKED_ROLLBACK, tx.state());
+
+                    tx.close();
+                }
+            }
+        });
+    }
+
+    /**
+     * Test checking timeout on suspended transaction.
+     *
+     * @throws Exception If failed.
+     */
+    public void testTxTimeoutOnSuspend() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    final Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation, TX_TIMEOUT, 0);
+
+                    cache.put(1, 1);
+
+                    Thread.sleep(TX_TIMEOUT * 2);
+
+                    GridTestUtils.assertThrowsWithCause(new Callable<Object>() {
+                        @Override public Object call() throws Exception {
+                            tx.suspend();
+
+                            return null;
+                        }
+                    }, TransactionTimeoutException.class);
+
+                    assertEquals(MARKED_ROLLBACK, tx.state());
+
+                    tx.close();
+
+                    assertNull(cache.get(1));
+                }
+            }
+        });
+    }
+
+    /**
+     * Test start 1 transaction, suspendTx it. And then start another transaction, trying to write
+     * the same key and commit it.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSuspendTxAndStartNew() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation tx1Isolation : TransactionIsolation.values()) {
+                    for (TransactionIsolation tx2Isolation : TransactionIsolation.values()) {
+                        Transaction tx1 = ignite.transactions().txStart(OPTIMISTIC, tx1Isolation);
+
+                        cache.put(1, 1);
+
+                        tx1.suspend();
+
+                        assertFalse(cache.containsKey(1));
+
+                        Transaction tx2 = ignite.transactions().txStart(OPTIMISTIC, tx2Isolation);
+
+                        cache.put(1, 2);
+
+                        tx2.commit();
+
+                        assertEquals(2, (int)cache.get(1));
+
+                        tx1.resume();
+
+                        assertEquals(1, (int)cache.get(1));
+
+                        tx1.close();
+
+                        cache.removeAll();
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Test start 1 transaction, suspendTx it. And then start another transaction, trying to write
+     * the same key.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSuspendTxAndStartNewWithoutCommit() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation tx1Isolation : TransactionIsolation.values()) {
+                    for (TransactionIsolation tx2Isolation : TransactionIsolation.values()) {
+                        Transaction tx1 = ignite.transactions().txStart(OPTIMISTIC, tx1Isolation);
+
+                        cache.put(1, 1);
+
+                        tx1.suspend();
+
+                        assertFalse(cache.containsKey(1));
+
+                        Transaction tx2 = ignite.transactions().txStart(OPTIMISTIC, tx2Isolation);
+
+                        cache.put(1, 2);
+
+                        tx2.suspend();
+
+                        assertFalse(cache.containsKey(1));
+
+                        tx1.resume();
+
+                        assertEquals(1, (int)cache.get(1));
+
+                        tx1.suspend();
+
+                        tx2.resume();
+
+                        assertEquals(2, (int)cache.get(1));
+
+                        tx2.rollback();
+
+                        tx1.resume();
+                        tx1.rollback();
+
+                        cache.removeAll();
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Test we can resume and complete transaction if topology changed while transaction is suspended.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSuspendTxAndResumeAfterTopologyChange() throws Exception {
+        executeTestForAllCaches(new CI2Exc<Ignite, IgniteCache<Integer, Integer>>() {
+            @Override public void applyx(Ignite ignite, final IgniteCache<Integer, Integer> cache) throws Exception {
+                for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                    Transaction tx = ignite.transactions().txStart(OPTIMISTIC, isolation);
+
+                    cache.put(1, 1);
+
+                    tx.suspend();
+
+                    assertEquals(SUSPENDED, tx.state());
+
+                    try (IgniteEx g = startGrid(serversNumber() + 3)) {
+                        tx.resume();
+
+                        assertEquals(ACTIVE, tx.state());
+
+                        assertEquals(1, (int)cache.get(1));
+
+                        tx.commit();
+
+                        assertEquals(1, (int)cache.get(1));
+                    }
+
+                    cache.removeAll();
+                }
+            }
+        });
+    }
+
+    /**
+     * @return Cache configurations to test.
+     */
+    private List<CacheConfiguration<Integer, Integer>> cacheConfigurations() {
+        List<CacheConfiguration<Integer, Integer>> cfgs = new ArrayList<>();
+
+        cfgs.add(cacheConfiguration(PARTITIONED, 0, false));
+        cfgs.add(cacheConfiguration(PARTITIONED, 1, false));
+        cfgs.add(cacheConfiguration(PARTITIONED, 1, true));
+        cfgs.add(cacheConfiguration(REPLICATED, 0, false));
+
+        return cfgs;
+    }
+
+    /**
+     * @param cacheMode Cache mode.
+     * @param backups Number of backups.
+     * @param nearCache If {@code true} near cache is enabled.
+     * @return Cache configuration.
+     */
+    private CacheConfiguration<Integer, Integer> cacheConfiguration(
+        CacheMode cacheMode,
+        int backups,
+        boolean nearCache) {
+        CacheConfiguration<Integer, Integer> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
+
+        ccfg.setCacheMode(cacheMode);
+        ccfg.setAtomicityMode(TRANSACTIONAL);
+        ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+        if (cacheMode == PARTITIONED)
+            ccfg.setBackups(backups);
+
+        if (nearCache)
+            ccfg.setNearConfiguration(new NearCacheConfiguration<Integer, Integer>());
+
+        return ccfg;
+    }
+
+    /**
+     * @param c Closure.
+     * @throws Exception If failed.
+     */
+    private void executeTestForAllCaches(CI2<Ignite, IgniteCache<Integer, Integer>> c) throws Exception {
+        for (CacheConfiguration<Integer, Integer> ccfg : cacheConfigurations()) {
+            ignite(0).createCache(ccfg);
+
+            log.info("Run test for cache [cache=" + ccfg.getCacheMode() +
+                ", backups=" + ccfg.getBackups() +
+                ", near=" + (ccfg.getNearConfiguration() != null) + "]");
+
+            int srvNum = serversNumber();
+            if (serversNumber() > 1) {
+                ignite(serversNumber() + 1).createNearCache(ccfg.getName(), new NearCacheConfiguration<>());
+                srvNum += 2;
+            }
+
+            try {
+                for (int i = 0; i < srvNum; i++) {
+                    Ignite ignite = ignite(i);
+
+                    log.info("Run test for node [node=" + i + ", client=" + ignite.configuration().isClientMode() + ']');
+
+                    c.apply(ignite, ignite.<Integer, Integer>cache(ccfg.getName()));
+                }
+            }
+            finally {
+                ignite(0).destroyCache(ccfg.getName());
+            }
+        }
+    }
+
+    /**
+     * Closure with 2 parameters that can throw any exception.
+     *
+     * @param <E1> Type of first closure parameter.
+     * @param <E2> Type of second closure parameter.
+     */
+    public static abstract class CI2Exc<E1, E2> implements CI2<E1, E2> {
+        /**
+         * Closure body.
+         *
+         * @param e1 First closure argument.
+         * @param e2 Second closure argument.
+         * @throws Exception If failed.
+         */
+        public abstract void applyx(E1 e1, E2 e2) throws Exception;
+
+        /** {@inheritdoc} */
+        @Override public void apply(E1 e1, E2 e2) {
+            try {
+                applyx(e1, e2);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Closure that can throw any exception.
+     *
+     * @param <T> Type of closure parameter.
+     */
+    public static abstract class CI1Exc<T> implements CI1<T> {
+        /**
+         * Closure body.
+         *
+         * @param o Closure argument.
+         * @throws Exception If failed.
+         */
+        public abstract void applyx(T o) throws Exception;
+
+        /** {@inheritdoc} */
+        @Override public void apply(T o) {
+            try {
+                applyx(o);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Runnable that can throw any exception.
+     */
+    public static abstract class RunnableX implements Runnable {
+        /**
+         * Closure body.
+         *
+         * @throws Exception If failed.
+         */
+        public abstract void runx() throws Exception;
+
+        /** {@inheritdoc} */
+        @Override public void run() {
+            try {
+                runx();
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java
new file mode 100644
index 0000000..57a1470
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgnitePessimisticTxSuspendResumeTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.util.concurrent.Callable;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteTransactions;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+
+/**
+ *
+ */
+public class IgnitePessimisticTxSuspendResumeTest extends GridCommonAbstractTest {
+    /**
+     * Creates new cache configuration.
+     *
+     * @return CacheConfiguration New cache configuration.
+     */
+    protected CacheConfiguration<Integer, String> getCacheConfiguration() {
+        CacheConfiguration<Integer, String> cacheCfg = defaultCacheConfiguration();
+
+        cacheCfg.setCacheMode(PARTITIONED);
+
+        return cacheCfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setClientMode(false);
+        cfg.setCacheConfiguration(getCacheConfiguration());
+
+        return cfg;
+    }
+
+    /**
+     * Test for suspension on pessimistic transaction.
+     *
+     * @throws Exception If failed.
+     */
+    public void testSuspendPessimisticTx() throws Exception {
+        try (Ignite g = startGrid()) {
+            IgniteCache<Integer, String> cache = jcache();
+
+            IgniteTransactions txs = g.transactions();
+
+            for (TransactionIsolation isolation : TransactionIsolation.values()) {
+                final Transaction tx = txs.txStart(TransactionConcurrency.PESSIMISTIC, isolation);
+
+                cache.put(1, "1");
+
+                GridTestUtils.assertThrowsWithCause(new Callable<Object>() {
+                    @Override public Object call() throws Exception {
+                        tx.suspend();
+
+                        return null;
+                    }
+                }, UnsupportedOperationException.class);
+
+                tx.close();
+
+                assertNull(cache.get(1));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
index cbcbaee..585c759 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
@@ -426,6 +426,32 @@ public final class GridTestUtils {
     }
 
     /**
+     * Checks whether closure throws exception, which is itself of a specified
+     * class, or has a cause of the specified class.
+     *
+     * @param call Closure.
+     * @param p Parameter passed to closure.
+     * @param cls Expected class.
+     * @return Thrown throwable.
+     */
+    public static <P> Throwable assertThrowsWithCause(IgniteInClosure<P> call, P p, Class<? extends Throwable> cls) {
+        assert call != null;
+        assert cls != null;
+
+        try {
+            call.apply(p);
+        }
+        catch (Throwable e) {
+            if (!X.hasCause(e, cls))
+                fail("Exception is neither of a specified class, nor has a cause of the specified class: " + cls, e);
+
+            return e;
+        }
+
+        throw new AssertionError("Exception has not been thrown.");
+    }
+
+    /**
      * Throw assertion error with specified error message and initialized cause.
      *
      * @param msg Error message.

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
index c5673b3..f764212 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
@@ -579,6 +579,16 @@ public abstract class GridAbstractCacheStoreSelfTest<T extends CacheStore<Object
         }
 
         /** {@inheritDoc} */
+        @Override public void suspend() {
+            // No-op.
+        }
+
+        /** {@inheritDoc} */
+        @Override public void resume() {
+            // No-op.
+        }
+
+        /** {@inheritDoc} */
         @Override public IgniteFuture<Void> rollbackAsync() throws IgniteException {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
new file mode 100644
index 0000000..90190d0
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
@@ -0,0 +1,42 @@
+/*
+ * 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.testsuites;
+
+import junit.framework.TestSuite;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteOptimisticTxSuspendResumeMultiServerTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteOptimisticTxSuspendResumeTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgnitePessimisticTxSuspendResumeTest;
+
+/**
+ * Test suite.
+ */
+public class IgniteCacheTestSuite6 extends TestSuite {
+    /**
+     * @return IgniteCache test suite.
+     * @throws Exception Thrown in case of the failure.
+     */
+    public static TestSuite suite() throws Exception {
+        TestSuite suite = new TestSuite("IgniteCache Test Suite part 6");
+
+        suite.addTestSuite(IgniteOptimisticTxSuspendResumeTest.class);
+        suite.addTestSuite(IgniteOptimisticTxSuspendResumeMultiServerTest.class);
+        suite.addTestSuite(IgnitePessimisticTxSuspendResumeTest.class);
+
+        return suite;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
----------------------------------------------------------------------
diff --git a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
index 5047491..dd5f6b7 100644
--- a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
+++ b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
@@ -28,10 +28,11 @@ import org.apache.ignite.cache.jta.CacheTmLookup;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.TransactionConfiguration;
 import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
-import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
 import org.apache.ignite.lifecycle.LifecycleAware;
 import org.jetbrains.annotations.Nullable;
 
+import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
+
 /**
  * Implementation of {@link CacheJtaManagerAdapter}.
  */
@@ -147,7 +148,7 @@ public class CacheJtaManager extends CacheJtaManagerAdapter {
         if (jtaTm != null) {
             CacheJtaResource rsrc = this.rsrc.get();
 
-            if (rsrc == null || rsrc.isFinished()) {
+            if (rsrc == null || rsrc.isFinished() || rsrc.cacheTx().state() == SUSPENDED) {
                 try {
                     Transaction jtaTx = jtaTm.getTransaction();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaResource.java
----------------------------------------------------------------------
diff --git a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaResource.java b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaResource.java
index 649f7c4..e29c44b 100644
--- a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaResource.java
+++ b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaResource.java
@@ -71,12 +71,21 @@ final class CacheJtaResource implements XAResource, Synchronization {
     }
 
     /** {@inheritDoc} */
-    @Override public void start(Xid xid, int flags) {
+    @Override public void start(Xid xid, int flags) throws XAException {
         if (log.isDebugEnabled())
             log.debug("XA resource start(...) [xid=" + xid + ", flags=<" + flags(flags) + ">]");
 
         // Simply save global transaction id.
         this.xid = xid;
+
+        if ((flags & TMRESUME) == TMRESUME) {
+            try {
+                cacheTx.resume();
+            }
+            catch (IgniteCheckedException e) {
+                throwException("Failed to resume cache transaction: " + e.getMessage(), e);
+            }
+        }
     }
 
     /**
@@ -128,7 +137,7 @@ final class CacheJtaResource implements XAResource, Synchronization {
     }
 
     /** {@inheritDoc} */
-    @Override public void end(Xid xid, int flags) {
+    @Override public void end(Xid xid, int flags) throws XAException {
         assert this.xid.equals(xid);
 
         if (log.isDebugEnabled())
@@ -136,6 +145,14 @@ final class CacheJtaResource implements XAResource, Synchronization {
 
         if ((flags & TMFAIL) > 0)
             cacheTx.setRollbackOnly();
+        else if ((flags & TMSUSPEND) == TMSUSPEND) {
+            try {
+                cacheTx.suspend();
+            }
+            catch (IgniteCheckedException e) {
+                throwException("Failed to suspend cache transaction: " + e.getMessage(), e);
+            }
+        }
     }
 
     /** {@inheritDoc} */
@@ -297,6 +314,13 @@ final class CacheJtaResource implements XAResource, Synchronization {
         return state == COMMITTED || state == ROLLED_BACK;
     }
 
+    /**
+     * @return Internal tx
+     */
+    GridNearTxLocal cacheTx() {
+        return cacheTx;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(CacheJtaResource.class, this);

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/jta/src/test/java/org/apache/ignite/internal/processors/cache/GridJtaTransactionManagerSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/jta/src/test/java/org/apache/ignite/internal/processors/cache/GridJtaTransactionManagerSelfTest.java b/modules/jta/src/test/java/org/apache/ignite/internal/processors/cache/GridJtaTransactionManagerSelfTest.java
new file mode 100644
index 0000000..a181068
--- /dev/null
+++ b/modules/jta/src/test/java/org/apache/ignite/internal/processors/cache/GridJtaTransactionManagerSelfTest.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import javax.cache.configuration.Factory;
+import javax.transaction.Transaction;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+import org.objectweb.jotm.Current;
+import org.objectweb.jotm.Jotm;
+import org.objectweb.transaction.jta.TransactionManager;
+
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.transactions.TransactionState.ACTIVE;
+
+/**
+ * JTA Tx Manager test.
+ */
+public class GridJtaTransactionManagerSelfTest extends GridCommonAbstractTest {
+    /** Java Open Transaction Manager facade. */
+    private static Jotm jotm;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName).
+            setCacheConfiguration(defaultCacheConfiguration().setCacheMode(PARTITIONED));
+
+        cfg.getTransactionConfiguration().setTxManagerFactory(new Factory<TransactionManager>() {
+            private static final long serialVersionUID = 0L;
+
+            @Override public TransactionManager create() {
+                return jotm.getTransactionManager();
+            }
+        });
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        jotm = new Jotm(true, false);
+
+        Current.setAppServer(false);
+
+        startGrid();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        super.afterTestsStopped();
+
+        stopAllGrids();
+
+        jotm.stop();
+    }
+
+    /**
+     * Test for switching tx context by JTA Manager.
+     *
+     * @throws Exception If failed.
+     */
+    public void testJtaTxContextSwitch() throws Exception {
+        for (TransactionIsolation isolation : TransactionIsolation.values()) {
+            TransactionConfiguration cfg = grid().context().config().getTransactionConfiguration();
+
+            cfg.setDefaultTxConcurrency(TransactionConcurrency.OPTIMISTIC);
+            cfg.setDefaultTxIsolation(isolation);
+
+            TransactionManager jtaTm = jotm.getTransactionManager();
+
+            IgniteCache<Integer, String> cache = jcache();
+
+            assertNull(grid().transactions().tx());
+
+            jtaTm.begin();
+
+            Transaction tx1 = jtaTm.getTransaction();
+
+            cache.put(1, Integer.toString(1));
+
+            assertNotNull(grid().transactions().tx());
+
+            assertEquals(ACTIVE, grid().transactions().tx().state());
+
+            assertEquals(Integer.toString(1), cache.get(1));
+
+            jtaTm.suspend();
+
+            assertNull(grid().transactions().tx());
+
+            assertNull(cache.get(1));
+
+            jtaTm.begin();
+
+            Transaction tx2 = jtaTm.getTransaction();
+
+            assertNotSame(tx1, tx2);
+
+            cache.put(2, Integer.toString(2));
+
+            assertNotNull(grid().transactions().tx());
+
+            assertEquals(ACTIVE, grid().transactions().tx().state());
+
+            assertEquals(Integer.toString(2), cache.get(2));
+
+            jtaTm.commit();
+
+            assertNull(grid().transactions().tx());
+
+            assertEquals(Integer.toString(2), cache.get(2));
+
+            jtaTm.resume(tx1);
+
+            assertNotNull(grid().transactions().tx());
+
+            assertEquals(ACTIVE, grid().transactions().tx().state());
+
+            cache.put(3, Integer.toString(3));
+
+            jtaTm.commit();
+
+            assertEquals("1", cache.get(1));
+            assertEquals("2", cache.get(2));
+            assertEquals("3", cache.get(3));
+
+            assertNull(grid().transactions().tx());
+
+            cache.removeAll();
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testJtaTxContextSwitchWithExistingTx() throws Exception {
+        for (TransactionIsolation isolation : TransactionIsolation.values()) {
+            TransactionConfiguration cfg = grid().context().config().getTransactionConfiguration();
+
+            cfg.setDefaultTxConcurrency(TransactionConcurrency.OPTIMISTIC);
+            cfg.setDefaultTxIsolation(isolation);
+
+            TransactionManager jtaTm = jotm.getTransactionManager();
+
+            IgniteCache<Integer, String> cache = jcache();
+
+            jtaTm.begin();
+
+            Transaction tx1 = jtaTm.getTransaction();
+
+            cache.put(1, Integer.toString(1));
+
+            assertNotNull(grid().transactions().tx());
+
+            assertEquals(ACTIVE, grid().transactions().tx().state());
+
+            assertEquals(Integer.toString(1), cache.get(1));
+
+            jtaTm.suspend();
+
+            jtaTm.begin();
+
+            Transaction tx2 = jtaTm.getTransaction();
+
+            assertNotSame(tx1, tx2);
+
+            cache.put(2, Integer.toString(2));
+
+            try {
+                jtaTm.resume(tx1);
+
+                fail("jtaTm.resume shouldn't success.");
+            }
+            catch (IllegalStateException ignored) {
+                // No-op.
+            }
+            finally {
+                jtaTm.rollback(); //rolling back tx2
+            }
+
+            jtaTm.resume(tx1);
+            jtaTm.rollback();
+
+            cache.removeAll();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e255a564/modules/jta/src/test/java/org/apache/ignite/testsuites/IgniteJtaTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/jta/src/test/java/org/apache/ignite/testsuites/IgniteJtaTestSuite.java b/modules/jta/src/test/java/org/apache/ignite/testsuites/IgniteJtaTestSuite.java
index 4ae5df0..0775c1a 100644
--- a/modules/jta/src/test/java/org/apache/ignite/testsuites/IgniteJtaTestSuite.java
+++ b/modules/jta/src/test/java/org/apache/ignite/testsuites/IgniteJtaTestSuite.java
@@ -21,13 +21,14 @@ import junit.framework.TestSuite;
 import org.apache.ignite.internal.processors.cache.CacheJndiTmFactorySelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheJtaConfigurationValidationSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheJtaFactoryConfigValidationSelfTest;
+import org.apache.ignite.internal.processors.cache.GridJtaLifecycleAwareSelfTest;
+import org.apache.ignite.internal.processors.cache.GridJtaTransactionManagerSelfTest;
 import org.apache.ignite.internal.processors.cache.GridPartitionedCacheJtaFactorySelfTest;
 import org.apache.ignite.internal.processors.cache.GridPartitionedCacheJtaFactoryUseSyncSelfTest;
 import org.apache.ignite.internal.processors.cache.GridPartitionedCacheJtaLookupClassNameSelfTest;
 import org.apache.ignite.internal.processors.cache.GridReplicatedCacheJtaFactorySelfTest;
 import org.apache.ignite.internal.processors.cache.GridReplicatedCacheJtaFactoryUseSyncSelfTest;
 import org.apache.ignite.internal.processors.cache.GridReplicatedCacheJtaLookupClassNameSelfTest;
-import org.apache.ignite.internal.processors.cache.GridJtaLifecycleAwareSelfTest;
 import org.apache.ignite.testframework.IgniteTestSuite;
 
 /**
@@ -54,6 +55,8 @@ public class IgniteJtaTestSuite extends TestSuite {
         suite.addTestSuite(GridCacheJtaConfigurationValidationSelfTest.class);
         suite.addTestSuite(GridCacheJtaFactoryConfigValidationSelfTest.class);
 
+        suite.addTestSuite(GridJtaTransactionManagerSelfTest.class);
+
         // Factory
         suite.addTestSuite(CacheJndiTmFactorySelfTest.class);
 


[10/29] ignite git commit: IGNITE-5211: Added new constructor: QueryEntity(Class keyCls, Class valCls). This closes #2371. This closes #2388. This closes #2407.

Posted by nt...@apache.org.
IGNITE-5211: Added new constructor: QueryEntity(Class keyCls, Class valCls). This closes #2371. This closes #2388. This closes #2407.


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

Branch: refs/heads/ignite-5947
Commit: b093afb8231135a4904f5fffd62f5b4c332f1d47
Parents: 4f02504
Author: tledkov-gridgain <tl...@gridgain.com>
Authored: Tue Aug 8 12:05:36 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Tue Aug 8 12:14:07 2017 +0300

----------------------------------------------------------------------
 .../org/apache/ignite/cache/QueryEntity.java    | 229 +++++++
 .../configuration/CacheConfiguration.java       | 620 +------------------
 .../cache/query/QueryEntityClassProperty.java   | 116 ++++
 .../cache/query/QueryEntityIndexDescriptor.java | 121 ++++
 .../cache/query/QueryEntityTypeDescriptor.java  | 219 +++++++
 .../h2/sql/AbstractH2CompareQueryTest.java      |   4 +-
 6 files changed, 693 insertions(+), 616 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/b093afb8/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
index 955e7d2..5180100 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
@@ -18,7 +18,9 @@
 package org.apache.ignite.cache;
 
 import java.io.Serializable;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -27,10 +29,20 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import javax.cache.CacheException;
+import org.apache.ignite.cache.query.annotations.QueryGroupIndex;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.cache.query.annotations.QueryTextField;
+import org.apache.ignite.internal.processors.cache.query.QueryEntityClassProperty;
+import org.apache.ignite.internal.processors.cache.query.QueryEntityTypeDescriptor;
+import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
+import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Query entity is a description of {@link org.apache.ignite.IgniteCache cache} entry (composed of key and value)
@@ -111,6 +123,16 @@ public class QueryEntity implements Serializable {
     }
 
     /**
+     * Creates a query entity with the given key and value types.
+     *
+     * @param keyCls Key type.
+     * @param valCls Value type.
+     */
+    public QueryEntity(Class<?> keyCls, Class<?> valCls) {
+        this(convert(processKeyAndValueClasses(keyCls,valCls)));
+    }
+
+    /**
      * Gets key type for this query pair.
      *
      * @return Key type.
@@ -351,6 +373,213 @@ public class QueryEntity implements Serializable {
         return this;
     }
 
+    /**
+     * @param desc Type descriptor.
+     * @return Type metadata.
+     */
+    private static QueryEntity convert(QueryEntityTypeDescriptor desc) {
+        QueryEntity entity = new QueryEntity();
+
+        // Key and val types.
+        entity.setKeyType(desc.keyClass().getName());
+        entity.setValueType(desc.valueClass().getName());
+
+        for (QueryEntityClassProperty prop : desc.properties().values())
+            entity.addQueryField(prop.fullName(), U.box(prop.type()).getName(), prop.alias());
+
+        entity.setKeyFields(desc.keyProperties());
+
+        QueryIndex txtIdx = null;
+
+        Collection<QueryIndex> idxs = new ArrayList<>();
+
+        for (Map.Entry<String, GridQueryIndexDescriptor> idxEntry : desc.indexes().entrySet()) {
+            GridQueryIndexDescriptor idx = idxEntry.getValue();
+
+            if (idx.type() == QueryIndexType.FULLTEXT) {
+                assert txtIdx == null;
+
+                txtIdx = new QueryIndex();
+
+                txtIdx.setIndexType(QueryIndexType.FULLTEXT);
+
+                txtIdx.setFieldNames(idx.fields(), true);
+                txtIdx.setName(idxEntry.getKey());
+            }
+            else {
+                QueryIndex sortedIdx = new QueryIndex();
+
+                sortedIdx.setIndexType(idx.type());
+
+                LinkedHashMap<String, Boolean> fields = new LinkedHashMap<>();
+
+                for (String f : idx.fields())
+                    fields.put(f, !idx.descending(f));
+
+                sortedIdx.setFields(fields);
+
+                sortedIdx.setName(idxEntry.getKey());
+
+                idxs.add(sortedIdx);
+            }
+        }
+
+        if (desc.valueTextIndex()) {
+            if (txtIdx == null) {
+                txtIdx = new QueryIndex();
+
+                txtIdx.setIndexType(QueryIndexType.FULLTEXT);
+
+                txtIdx.setFieldNames(Arrays.asList(QueryUtils.VAL_FIELD_NAME), true);
+            }
+            else
+                txtIdx.getFields().put(QueryUtils.VAL_FIELD_NAME, true);
+        }
+
+        if (txtIdx != null)
+            idxs.add(txtIdx);
+
+        if (!F.isEmpty(idxs))
+            entity.setIndexes(idxs);
+
+        return entity;
+    }
+
+    /**
+     * @param keyCls Key class.
+     * @param valCls Value class.
+     * @return Type descriptor.
+     */
+    private static QueryEntityTypeDescriptor processKeyAndValueClasses(
+        Class<?> keyCls,
+        Class<?> valCls
+    ) {
+        QueryEntityTypeDescriptor d = new QueryEntityTypeDescriptor();
+
+        d.keyClass(keyCls);
+        d.valueClass(valCls);
+
+        processAnnotationsInClass(true, d.keyClass(), d, null);
+        processAnnotationsInClass(false, d.valueClass(), d, null);
+
+        return d;
+    }
+
+    /**
+     * Process annotations for class.
+     *
+     * @param key If given class relates to key.
+     * @param cls Class.
+     * @param type Type descriptor.
+     * @param parent Parent in case of embeddable.
+     */
+    private static void processAnnotationsInClass(boolean key, Class<?> cls, QueryEntityTypeDescriptor type,
+        @Nullable QueryEntityClassProperty parent) {
+        if (U.isJdk(cls) || QueryUtils.isGeometryClass(cls)) {
+            if (parent == null && !key && QueryUtils.isSqlType(cls)) { // We have to index primitive _val.
+                String idxName = cls.getSimpleName() + "_" + QueryUtils.VAL_FIELD_NAME + "_idx";
+
+                type.addIndex(idxName, QueryUtils.isGeometryClass(cls) ?
+                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
+
+                type.addFieldToIndex(idxName, QueryUtils.VAL_FIELD_NAME, 0, false);
+            }
+
+            return;
+        }
+
+        if (parent != null && parent.knowsClass(cls))
+            throw new CacheException("Recursive reference found in type: " + cls.getName());
+
+        if (parent == null) { // Check class annotation at top level only.
+            QueryTextField txtAnnCls = cls.getAnnotation(QueryTextField.class);
+
+            if (txtAnnCls != null)
+                type.valueTextIndex(true);
+
+            QueryGroupIndex grpIdx = cls.getAnnotation(QueryGroupIndex.class);
+
+            if (grpIdx != null)
+                type.addIndex(grpIdx.name(), QueryIndexType.SORTED);
+
+            QueryGroupIndex.List grpIdxList = cls.getAnnotation(QueryGroupIndex.List.class);
+
+            if (grpIdxList != null && !F.isEmpty(grpIdxList.value())) {
+                for (QueryGroupIndex idx : grpIdxList.value())
+                    type.addIndex(idx.name(), QueryIndexType.SORTED);
+            }
+        }
+
+        for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
+            for (Field field : c.getDeclaredFields()) {
+                QuerySqlField sqlAnn = field.getAnnotation(QuerySqlField.class);
+                QueryTextField txtAnn = field.getAnnotation(QueryTextField.class);
+
+                if (sqlAnn != null || txtAnn != null) {
+                    QueryEntityClassProperty prop = new QueryEntityClassProperty(field);
+
+                    prop.parent(parent);
+
+                    // Add parent property before its possible nested properties so that
+                    // resulting parent column comes before columns corresponding to those
+                    // nested properties in the resulting table - that way nested
+                    // properties override will happen properly (first parent, then children).
+                    type.addProperty(prop, key, true);
+
+                    processAnnotation(key, sqlAnn, txtAnn, cls, c, field.getType(), prop, type);
+                }
+            }
+        }
+    }
+
+    /**
+     * Processes annotation at field or method.
+     *
+     * @param key If given class relates to key.
+     * @param sqlAnn SQL annotation, can be {@code null}.
+     * @param txtAnn H2 text annotation, can be {@code null}.
+     * @param cls Entity class.
+     * @param curCls Current entity class.
+     * @param fldCls Class of field or return type for method.
+     * @param prop Current property.
+     * @param desc Class description.
+     */
+    private static void processAnnotation(boolean key, QuerySqlField sqlAnn, QueryTextField txtAnn,
+        Class<?> cls, Class<?> curCls, Class<?> fldCls, QueryEntityClassProperty prop, QueryEntityTypeDescriptor desc) {
+        if (sqlAnn != null) {
+            processAnnotationsInClass(key, fldCls, desc, prop);
+
+            if (!sqlAnn.name().isEmpty())
+                prop.alias(sqlAnn.name());
+
+            if (sqlAnn.index()) {
+                String idxName = curCls.getSimpleName() + "_" + prop.alias() + "_idx";
+
+                if (cls != curCls)
+                    idxName = cls.getSimpleName() + "_" + idxName;
+
+                desc.addIndex(idxName, QueryUtils.isGeometryClass(prop.type()) ?
+                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
+
+                desc.addFieldToIndex(idxName, prop.fullName(), 0, sqlAnn.descending());
+            }
+
+            if (!F.isEmpty(sqlAnn.groups())) {
+                for (String group : sqlAnn.groups())
+                    desc.addFieldToIndex(group, prop.fullName(), 0, false);
+            }
+
+            if (!F.isEmpty(sqlAnn.orderedGroups())) {
+                for (QuerySqlField.Group idx : sqlAnn.orderedGroups())
+                    desc.addFieldToIndex(idx.name(), prop.fullName(), idx.order(), idx.descending());
+            }
+        }
+
+        if (txtAnn != null)
+            desc.addFieldToTextIndex(prop.fullName());
+    }
+
+
     /** {@inheritDoc} */
     @Override public boolean equals(Object o) {
         if (this == o)

http://git-wip-us.apache.org/repos/asf/ignite/blob/b093afb8/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
index 670046f..2b4ec1d 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
@@ -18,21 +18,10 @@
 package org.apache.ignite.configuration;
 
 import java.io.Serializable;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
 import javax.cache.Cache;
 import javax.cache.CacheException;
 import javax.cache.configuration.CacheEntryListenerConfiguration;
@@ -53,26 +42,17 @@ import org.apache.ignite.cache.CacheRebalanceMode;
 import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.cache.PartitionLossPolicy;
 import org.apache.ignite.cache.QueryEntity;
-import org.apache.ignite.cache.QueryIndex;
-import org.apache.ignite.cache.QueryIndexType;
 import org.apache.ignite.cache.affinity.AffinityFunction;
 import org.apache.ignite.cache.affinity.AffinityKeyMapper;
 import org.apache.ignite.cache.eviction.EvictionFilter;
 import org.apache.ignite.cache.eviction.EvictionPolicy;
-import org.apache.ignite.cache.query.annotations.QueryGroupIndex;
-import org.apache.ignite.cache.query.annotations.QuerySqlField;
 import org.apache.ignite.cache.query.annotations.QuerySqlFunction;
-import org.apache.ignite.cache.query.annotations.QueryTextField;
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cache.store.CacheStoreSessionListener;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.binary.BinaryContext;
-import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
 import org.apache.ignite.internal.processors.query.QueryUtils;
-import org.apache.ignite.internal.util.tostring.GridToStringExclude;
-import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -1768,14 +1748,12 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
             Class<?> keyCls = newIndexedTypes[i];
             Class<?> valCls = newIndexedTypes[i + 1];
 
-            TypeDescriptor desc = processKeyAndValueClasses(keyCls, valCls);
-
-            QueryEntity converted = convert(desc);
+            QueryEntity newEntity = new QueryEntity(keyCls, valCls);
 
             boolean dup = false;
 
             for (QueryEntity entity : qryEntities) {
-                if (F.eq(entity.findValueType(), converted.findValueType())) {
+                if (F.eq(entity.findValueType(), newEntity.findValueType())) {
                     dup = true;
 
                     break;
@@ -1783,13 +1761,13 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
             }
 
             if (!dup)
-                qryEntities.add(converted);
+                qryEntities.add(newEntity);
 
             // Set key configuration if needed.
-            String affFieldName = desc.affinityFieldName();
+            String affFieldName = BinaryContext.affinityFieldName(keyCls);
 
             if (affFieldName != null) {
-                CacheKeyConfiguration newKeyCfg = new CacheKeyConfiguration(converted.getKeyType(), affFieldName);
+                CacheKeyConfiguration newKeyCfg = new CacheKeyConfiguration(newEntity.getKeyType(), affFieldName);
 
                 if (F.isEmpty(keyCfg))
                     keyCfg = new CacheKeyConfiguration[] { newKeyCfg };
@@ -2041,82 +2019,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
         return cfg;
     }
 
-    /**
-     * @param desc Type descriptor.
-     * @return Type metadata.
-     */
-    private static QueryEntity convert(TypeDescriptor desc) {
-        QueryEntity entity = new QueryEntity();
-
-        // Key and val types.
-        entity.setKeyType(desc.keyClass().getName());
-        entity.setValueType(desc.valueClass().getName());
-
-        for (ClassProperty prop : desc.props.values())
-            entity.addQueryField(prop.fullName(), U.box(prop.type()).getName(), prop.alias());
-
-        entity.setKeyFields(desc.keyProps);
-
-        QueryIndex txtIdx = null;
-
-        Collection<QueryIndex> idxs = new ArrayList<>();
-
-        for (Map.Entry<String, GridQueryIndexDescriptor> idxEntry : desc.indexes().entrySet()) {
-            GridQueryIndexDescriptor idx = idxEntry.getValue();
-
-            if (idx.type() == QueryIndexType.FULLTEXT) {
-                assert txtIdx == null;
-
-                txtIdx = new QueryIndex();
-
-                txtIdx.setIndexType(QueryIndexType.FULLTEXT);
-
-                txtIdx.setFieldNames(idx.fields(), true);
-                txtIdx.setName(idxEntry.getKey());
-            }
-            else {
-                Collection<String> grp = new ArrayList<>();
-
-                for (String fieldName : idx.fields())
-                    grp.add(idx.descending(fieldName) ? fieldName + " desc" : fieldName);
-
-                QueryIndex sortedIdx = new QueryIndex();
-
-                sortedIdx.setIndexType(idx.type());
-
-                LinkedHashMap<String, Boolean> fields = new LinkedHashMap<>();
-
-                for (String f : idx.fields())
-                    fields.put(f, !idx.descending(f));
-
-                sortedIdx.setFields(fields);
-
-                sortedIdx.setName(idxEntry.getKey());
-
-                idxs.add(sortedIdx);
-            }
-        }
-
-        if (desc.valueTextIndex()) {
-            if (txtIdx == null) {
-                txtIdx = new QueryIndex();
-
-                txtIdx.setIndexType(QueryIndexType.FULLTEXT);
-
-                txtIdx.setFieldNames(Arrays.asList(QueryUtils.VAL_FIELD_NAME), true);
-            }
-            else
-                txtIdx.getFields().put(QueryUtils.VAL_FIELD_NAME, true);
-        }
-
-        if (txtIdx != null)
-            idxs.add(txtIdx);
-
-        if (!F.isEmpty(idxs))
-            entity.setIndexes(idxs);
-
-        return entity;
-    }
 
     /**
      * @param cls Class.
@@ -2128,141 +2030,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
         return QueryUtils.isSqlType(cls) ? cls : Object.class;
     }
 
-    /**
-     * @param keyCls Key class.
-     * @param valCls Value class.
-     * @return Type descriptor.
-     */
-    static TypeDescriptor processKeyAndValueClasses(
-        Class<?> keyCls,
-        Class<?> valCls
-    ) {
-        TypeDescriptor d = new TypeDescriptor();
-
-        d.keyClass(keyCls);
-        d.valueClass(valCls);
-
-        d.affinityFieldName(BinaryContext.affinityFieldName(keyCls));
-
-        processAnnotationsInClass(true, d.keyCls, d, null);
-        processAnnotationsInClass(false, d.valCls, d, null);
-
-        return d;
-    }
-
-    /**
-     * Process annotations for class.
-     *
-     * @param key If given class relates to key.
-     * @param cls Class.
-     * @param type Type descriptor.
-     * @param parent Parent in case of embeddable.
-     */
-    private static void processAnnotationsInClass(boolean key, Class<?> cls, TypeDescriptor type,
-        @Nullable ClassProperty parent) {
-        if (U.isJdk(cls) || QueryUtils.isGeometryClass(cls)) {
-            if (parent == null && !key && QueryUtils.isSqlType(cls)) { // We have to index primitive _val.
-                String idxName = cls.getSimpleName() + "_" + QueryUtils.VAL_FIELD_NAME + "_idx";
-
-                type.addIndex(idxName, QueryUtils.isGeometryClass(cls) ?
-                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
-
-                type.addFieldToIndex(idxName, QueryUtils.VAL_FIELD_NAME, 0, false);
-            }
-
-            return;
-        }
-
-        if (parent != null && parent.knowsClass(cls))
-            throw new CacheException("Recursive reference found in type: " + cls.getName());
-
-        if (parent == null) { // Check class annotation at top level only.
-            QueryTextField txtAnnCls = cls.getAnnotation(QueryTextField.class);
-
-            if (txtAnnCls != null)
-                type.valueTextIndex(true);
-
-            QueryGroupIndex grpIdx = cls.getAnnotation(QueryGroupIndex.class);
-
-            if (grpIdx != null)
-                type.addIndex(grpIdx.name(), QueryIndexType.SORTED);
-
-            QueryGroupIndex.List grpIdxList = cls.getAnnotation(QueryGroupIndex.List.class);
-
-            if (grpIdxList != null && !F.isEmpty(grpIdxList.value())) {
-                for (QueryGroupIndex idx : grpIdxList.value())
-                    type.addIndex(idx.name(), QueryIndexType.SORTED);
-            }
-        }
-
-        for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
-            for (Field field : c.getDeclaredFields()) {
-                QuerySqlField sqlAnn = field.getAnnotation(QuerySqlField.class);
-                QueryTextField txtAnn = field.getAnnotation(QueryTextField.class);
-
-                if (sqlAnn != null || txtAnn != null) {
-                    ClassProperty prop = new ClassProperty(field);
-
-                    prop.parent(parent);
-
-                    // Add parent property before its possible nested properties so that
-                    // resulting parent column comes before columns corresponding to those
-                    // nested properties in the resulting table - that way nested
-                    // properties override will happen properly (first parent, then children).
-                    type.addProperty(prop, key, true);
-
-                    processAnnotation(key, sqlAnn, txtAnn, cls, c, field.getType(), prop, type);
-                }
-            }
-        }
-    }
-
-    /**
-     * Processes annotation at field or method.
-     *
-     * @param key If given class relates to key.
-     * @param sqlAnn SQL annotation, can be {@code null}.
-     * @param txtAnn H2 text annotation, can be {@code null}.
-     * @param cls Entity class.
-     * @param curCls Current entity class.
-     * @param fldCls Class of field or return type for method.
-     * @param prop Current property.
-     * @param desc Class description.
-     */
-    private static void processAnnotation(boolean key, QuerySqlField sqlAnn, QueryTextField txtAnn,
-        Class<?> cls, Class<?> curCls, Class<?> fldCls, ClassProperty prop, TypeDescriptor desc) {
-        if (sqlAnn != null) {
-            processAnnotationsInClass(key, fldCls, desc, prop);
-
-            if (!sqlAnn.name().isEmpty())
-                prop.alias(sqlAnn.name());
-
-            if (sqlAnn.index()) {
-                String idxName = curCls.getSimpleName() + "_" + prop.alias() + "_idx";
-
-                if (cls != curCls)
-                    idxName = cls.getSimpleName() + "_" + idxName;
-
-                desc.addIndex(idxName, QueryUtils.isGeometryClass(prop.type()) ?
-                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
-
-                desc.addFieldToIndex(idxName, prop.fullName(), 0, sqlAnn.descending());
-            }
-
-            if (!F.isEmpty(sqlAnn.groups())) {
-                for (String group : sqlAnn.groups())
-                    desc.addFieldToIndex(group, prop.fullName(), 0, false);
-            }
-
-            if (!F.isEmpty(sqlAnn.orderedGroups())) {
-                for (QuerySqlField.Group idx : sqlAnn.orderedGroups())
-                    desc.addFieldToIndex(idx.name(), prop.fullName(), idx.order(), idx.descending());
-            }
-        }
-
-        if (txtAnn != null)
-            desc.addFieldToTextIndex(prop.fullName());
-    }
 
     /** {@inheritDoc} */
     @Override public CacheConfiguration<K, V> setStatisticsEnabled(boolean enabled) {
@@ -2375,381 +2142,4 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
             return "IgniteAllNodesPredicate []";
         }
     }
-
-    /**
-     * Descriptor of type.
-     */
-    private static class TypeDescriptor {
-        /** Value field names and types with preserved order. */
-        @GridToStringInclude
-        private final Map<String, Class<?>> fields = new LinkedHashMap<>();
-
-        /** */
-        @GridToStringExclude
-        private final Map<String, ClassProperty> props = new LinkedHashMap<>();
-
-        /** */
-        @GridToStringInclude
-        private final Set<String> keyProps = new HashSet<>();
-
-        /** */
-        @GridToStringInclude
-        private final Map<String, IndexDescriptor> indexes = new HashMap<>();
-
-        /** */
-        private IndexDescriptor fullTextIdx;
-
-        /** */
-        private Class<?> keyCls;
-
-        /** */
-        private Class<?> valCls;
-
-        /** */
-        private boolean valTextIdx;
-
-        /** Affinity field name. */
-        private String affFieldName;
-
-        /**
-         * @return Indexes.
-         */
-        public Map<String, GridQueryIndexDescriptor> indexes() {
-            return Collections.<String, GridQueryIndexDescriptor>unmodifiableMap(indexes);
-        }
-
-        /**
-         * Adds index.
-         *
-         * @param idxName Index name.
-         * @param type Index type.
-         * @param inlineSize Inline size.
-         * @return Index descriptor.
-         */
-        public IndexDescriptor addIndex(String idxName, QueryIndexType type, int inlineSize) {
-            IndexDescriptor idx = new IndexDescriptor(type, inlineSize);
-
-            if (indexes.put(idxName, idx) != null)
-                throw new CacheException("Index with name '" + idxName + "' already exists.");
-
-            return idx;
-        }
-
-        /**
-         * Adds index.
-         *
-         * @param idxName Index name.
-         * @param type Index type.
-         * @return Index descriptor.
-         */
-        public IndexDescriptor addIndex(String idxName, QueryIndexType type) {
-            return addIndex(idxName, type, -1);
-        }
-
-        /**
-         * Adds field to index.
-         *
-         * @param idxName Index name.
-         * @param field Field name.
-         * @param orderNum Fields order number in index.
-         * @param descending Sorting order.
-         */
-        public void addFieldToIndex(String idxName, String field, int orderNum,
-            boolean descending) {
-            IndexDescriptor desc = indexes.get(idxName);
-
-            if (desc == null)
-                desc = addIndex(idxName, QueryIndexType.SORTED);
-
-            desc.addField(field, orderNum, descending);
-        }
-
-        /**
-         * Adds field to text index.
-         *
-         * @param field Field name.
-         */
-        public void addFieldToTextIndex(String field) {
-            if (fullTextIdx == null) {
-                fullTextIdx = new IndexDescriptor(QueryIndexType.FULLTEXT);
-
-                indexes.put(null, fullTextIdx);
-            }
-
-            fullTextIdx.addField(field, 0, false);
-        }
-
-        /**
-         * @return Value class.
-         */
-        public Class<?> valueClass() {
-            return valCls;
-        }
-
-        /**
-         * Sets value class.
-         *
-         * @param valCls Value class.
-         */
-        void valueClass(Class<?> valCls) {
-            this.valCls = valCls;
-        }
-
-        /**
-         * @return Key class.
-         */
-        public Class<?> keyClass() {
-            return keyCls;
-        }
-
-        /**
-         * Set key class.
-         *
-         * @param keyCls Key class.
-         */
-        void keyClass(Class<?> keyCls) {
-            this.keyCls = keyCls;
-        }
-
-        /**
-         * @return Affinity field name.
-         */
-        @Nullable public String affinityFieldName() {
-            return affFieldName;
-        }
-
-        /**
-         * @param affFieldName Affinity field name.
-         */
-        private void affinityFieldName(@Nullable String affFieldName) {
-            this.affFieldName = affFieldName;
-        }
-
-        /**
-         * Adds property to the type descriptor.
-         *
-         * @param prop Property.
-         * @param key Property ownership flag (key or not).
-         * @param failOnDuplicate Fail on duplicate flag.
-         */
-        void addProperty(ClassProperty prop, boolean key, boolean failOnDuplicate) {
-            String name = prop.fullName();
-
-            if (props.put(name, prop) != null && failOnDuplicate)
-                throw new CacheException("Property with name '" + name + "' already exists.");
-
-            fields.put(name, prop.type());
-
-            if (key)
-                keyProps.add(name);
-        }
-
-        /**
-         * @return {@code true} If we need to have a fulltext index on value.
-         */
-        public boolean valueTextIndex() {
-            return valTextIdx;
-        }
-
-        /**
-         * Sets if this value should be text indexed.
-         *
-         * @param valTextIdx Flag value.
-         */
-        public void valueTextIndex(boolean valTextIdx) {
-            this.valTextIdx = valTextIdx;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(TypeDescriptor.class, this);
-        }
-    }
-
-    /**
-     * Index descriptor.
-     */
-    private static class IndexDescriptor implements GridQueryIndexDescriptor {
-        /** Fields sorted by order number. */
-        private final Collection<T2<String, Integer>> fields = new TreeSet<>(
-            new Comparator<T2<String, Integer>>() {
-                @Override public int compare(T2<String, Integer> o1, T2<String, Integer> o2) {
-                    if (o1.get2().equals(o2.get2())) // Order is equal, compare field names to avoid replace in Set.
-                        return o1.get1().compareTo(o2.get1());
-
-                    return o1.get2() < o2.get2() ? -1 : 1;
-                }
-            });
-
-        /** Fields which should be indexed in descending order. */
-        private Collection<String> descendings;
-
-        /** */
-        private final QueryIndexType type;
-
-        /** */
-        private final int inlineSize;
-
-        /**
-         * @param type Type.
-         * @param inlineSize Inline size.
-         */
-        private IndexDescriptor(QueryIndexType type, int inlineSize) {
-            assert type != null;
-
-            this.type = type;
-            this.inlineSize = inlineSize;
-        }
-
-        /**
-         * @param type Type.
-         */
-        private IndexDescriptor(QueryIndexType type) {
-            this(type, -1);
-        }
-
-        /** {@inheritDoc} */
-        @Override public String name() {
-            return null;
-        }
-
-        /** {@inheritDoc} */
-        @Override public Collection<String> fields() {
-            Collection<String> res = new ArrayList<>(fields.size());
-
-            for (T2<String, Integer> t : fields)
-                res.add(t.get1());
-
-            return res;
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean descending(String field) {
-            return descendings != null && descendings.contains(field);
-        }
-
-        /**
-         * Adds field to this index.
-         *
-         * @param field Field name.
-         * @param orderNum Field order number in this index.
-         * @param descending Sort order.
-         */
-        public void addField(String field, int orderNum, boolean descending) {
-            fields.add(new T2<>(field, orderNum));
-
-            if (descending) {
-                if (descendings == null)
-                    descendings = new HashSet<>();
-
-                descendings.add(field);
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override public QueryIndexType type() {
-            return type;
-        }
-
-        /** {@inheritDoc} */
-        @Override public int inlineSize() {
-            return inlineSize;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(IndexDescriptor.class, this);
-        }
-    }
-
-    /**
-     * Description of type property.
-     */
-    private static class ClassProperty {
-        /** */
-        private final Member member;
-
-        /** */
-        private ClassProperty parent;
-
-        /** */
-        private String name;
-
-        /** */
-        private String alias;
-
-        /**
-         * Constructor.
-         *
-         * @param member Element.
-         */
-        ClassProperty(Member member) {
-            this.member = member;
-
-            name = member.getName();
-
-            if (member instanceof Method) {
-                if (member.getName().startsWith("get") && member.getName().length() > 3)
-                    name = member.getName().substring(3);
-
-                if (member.getName().startsWith("is") && member.getName().length() > 2)
-                    name = member.getName().substring(2);
-            }
-
-            ((AccessibleObject)member).setAccessible(true);
-        }
-
-        /**
-         * @param alias Alias.
-         */
-        public void alias(String alias) {
-            this.alias = alias;
-        }
-
-        /**
-         * @return Alias.
-         */
-        String alias() {
-            return F.isEmpty(alias) ? name : alias;
-        }
-
-        /**
-         * @return Type.
-         */
-        public Class<?> type() {
-            return member instanceof Field ? ((Field)member).getType() : ((Method)member).getReturnType();
-        }
-
-        /**
-         * @param parent Parent property if this is embeddable element.
-         */
-        public void parent(ClassProperty parent) {
-            this.parent = parent;
-        }
-
-        /** {@inheritDoc} */
-        @Override public String toString() {
-            return S.toString(ClassProperty.class, this);
-        }
-
-        /**
-         * @param cls Class.
-         * @return {@code true} If this property or some parent relates to member of the given class.
-         */
-        public boolean knowsClass(Class<?> cls) {
-            return member.getDeclaringClass() == cls || (parent != null && parent.knowsClass(cls));
-        }
-
-        /**
-         * @return Full name with all parents in dot notation.
-         */
-        public String fullName() {
-            assert name != null;
-
-            if (parent == null)
-                return name;
-
-            return parent.fullName() + '.' + name;
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/b093afb8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityClassProperty.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityClassProperty.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityClassProperty.java
new file mode 100644
index 0000000..e21b73c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityClassProperty.java
@@ -0,0 +1,116 @@
+/*
+ * 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.query;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ * Description of type property.
+ */
+public class QueryEntityClassProperty {
+    /** */
+    private final Member member;
+
+    /** */
+    private QueryEntityClassProperty parent;
+
+    /** */
+    private String name;
+
+    /** */
+    private String alias;
+
+    /**
+     * Constructor.
+     *
+     * @param member Element.
+     */
+    public QueryEntityClassProperty(Member member) {
+        this.member = member;
+
+        name = member.getName();
+
+        if (member instanceof Method) {
+            if (member.getName().startsWith("get") && member.getName().length() > 3)
+                name = member.getName().substring(3);
+
+            if (member.getName().startsWith("is") && member.getName().length() > 2)
+                name = member.getName().substring(2);
+        }
+
+        ((AccessibleObject)member).setAccessible(true);
+    }
+
+    /**
+     * @param alias Alias.
+     */
+    public void alias(String alias) {
+        this.alias = alias;
+    }
+
+    /**
+     * @return Alias.
+     */
+    public String alias() {
+        return F.isEmpty(alias) ? name : alias;
+    }
+
+    /**
+     * @return Type.
+     */
+    public Class<?> type() {
+        return member instanceof Field ? ((Field)member).getType() : ((Method)member).getReturnType();
+    }
+
+    /**
+     * @param parent Parent property if this is embeddable element.
+     */
+    public void parent(QueryEntityClassProperty parent) {
+        this.parent = parent;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(QueryEntityClassProperty.class, this);
+    }
+
+    /**
+     * @param cls Class.
+     * @return {@code true} If this property or some parent relates to member of the given class.
+     */
+    public boolean knowsClass(Class<?> cls) {
+        return member.getDeclaringClass() == cls || (parent != null && parent.knowsClass(cls));
+    }
+
+    /**
+     * @return Full name with all parents in dot notation.
+     */
+    public String fullName() {
+        assert name != null;
+
+        if (parent == null)
+            return name;
+
+        return parent.fullName() + '.' + name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b093afb8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityIndexDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityIndexDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityIndexDescriptor.java
new file mode 100644
index 0000000..2fb5837
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityIndexDescriptor.java
@@ -0,0 +1,121 @@
+/*
+ * 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.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.TreeSet;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ * Index descriptor.
+ */
+public class QueryEntityIndexDescriptor implements GridQueryIndexDescriptor {
+    /** Fields sorted by order number. */
+    private final Collection<T2<String, Integer>> fields = new TreeSet<>(
+        new Comparator<T2<String, Integer>>() {
+            @Override public int compare(T2<String, Integer> o1, T2<String, Integer> o2) {
+                if (o1.get2().equals(o2.get2())) // Order is equal, compare field names to avoid replace in Set.
+                    return o1.get1().compareTo(o2.get1());
+
+                return o1.get2() < o2.get2() ? -1 : 1;
+            }
+        });
+    /** */
+    private final QueryIndexType type;
+    /** */
+    private final int inlineSize;
+    /** Fields which should be indexed in descending order. */
+    private Collection<String> descendings;
+
+    /**
+     * @param type Type.
+     * @param inlineSize Inline size.
+     */
+    QueryEntityIndexDescriptor(QueryIndexType type, int inlineSize) {
+        assert type != null;
+
+        this.type = type;
+        this.inlineSize = inlineSize;
+    }
+
+    /**
+     * @param type Type.
+     */
+    QueryEntityIndexDescriptor(QueryIndexType type) {
+        this(type, -1);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String name() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<String> fields() {
+        Collection<String> res = new ArrayList<>(fields.size());
+
+        for (T2<String, Integer> t : fields)
+            res.add(t.get1());
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean descending(String field) {
+        return descendings != null && descendings.contains(field);
+    }
+
+    /**
+     * Adds field to this index.
+     *
+     * @param field Field name.
+     * @param orderNum Field order number in this index.
+     * @param descending Sort order.
+     */
+    public void addField(String field, int orderNum, boolean descending) {
+        fields.add(new T2<>(field, orderNum));
+
+        if (descending) {
+            if (descendings == null)
+                descendings = new HashSet<>();
+
+            descendings.add(field);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public QueryIndexType type() {
+        return type;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int inlineSize() {
+        return inlineSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(QueryEntityIndexDescriptor.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b093afb8/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
new file mode 100644
index 0000000..47ab263
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
@@ -0,0 +1,219 @@
+/*
+ * 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.query;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.cache.CacheException;
+import org.apache.ignite.cache.QueryIndexType;
+import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ * Descriptor of type.
+ */
+public class QueryEntityTypeDescriptor {
+    /** Value field names and types with preserved order. */
+    @GridToStringInclude
+    private final Map<String, Class<?>> fields = new LinkedHashMap<>();
+
+    /** */
+    @GridToStringExclude
+    private final Map<String, QueryEntityClassProperty> props = new LinkedHashMap<>();
+
+    /** */
+    @GridToStringInclude
+    private final Set<String> keyProps = new HashSet<>();
+
+    /** */
+    @GridToStringInclude
+    private final Map<String, QueryEntityIndexDescriptor> indexes = new HashMap<>();
+
+    /** */
+    private QueryEntityIndexDescriptor fullTextIdx;
+
+    /** */
+    private Class<?> keyCls;
+
+    /** */
+    private Class<?> valCls;
+
+    /** */
+    private boolean valTextIdx;
+
+    /**
+     * @return Indexes.
+     */
+    public Map<String, GridQueryIndexDescriptor> indexes() {
+        return Collections.<String, GridQueryIndexDescriptor>unmodifiableMap(indexes);
+    }
+
+    /**
+     * Adds index.
+     *
+     * @param idxName Index name.
+     * @param type Index type.
+     * @param inlineSize Inline size.
+     * @return Index descriptor.
+     */
+    public QueryEntityIndexDescriptor addIndex(String idxName, QueryIndexType type, int inlineSize) {
+        QueryEntityIndexDescriptor idx = new QueryEntityIndexDescriptor(type, inlineSize);
+
+        if (indexes.put(idxName, idx) != null)
+            throw new CacheException("Index with name '" + idxName + "' already exists.");
+
+        return idx;
+    }
+
+    /**
+     * Adds index.
+     *
+     * @param idxName Index name.
+     * @param type Index type.
+     * @return Index descriptor.
+     */
+    public QueryEntityIndexDescriptor addIndex(String idxName, QueryIndexType type) {
+        return addIndex(idxName, type, -1);
+    }
+
+    /**
+     * Adds field to index.
+     *
+     * @param idxName Index name.
+     * @param field Field name.
+     * @param orderNum Fields order number in index.
+     * @param descending Sorting order.
+     */
+    public void addFieldToIndex(String idxName, String field, int orderNum,
+        boolean descending) {
+        QueryEntityIndexDescriptor desc = indexes.get(idxName);
+
+        if (desc == null)
+            desc = addIndex(idxName, QueryIndexType.SORTED);
+
+        desc.addField(field, orderNum, descending);
+    }
+
+    /**
+     * Adds field to text index.
+     *
+     * @param field Field name.
+     */
+    public void addFieldToTextIndex(String field) {
+        if (fullTextIdx == null) {
+            fullTextIdx = new QueryEntityIndexDescriptor(QueryIndexType.FULLTEXT);
+
+            indexes.put(null, fullTextIdx);
+        }
+
+        fullTextIdx.addField(field, 0, false);
+    }
+
+    /**
+     * @return Value class.
+     */
+    public Class<?> valueClass() {
+        return valCls;
+    }
+
+    /**
+     * Sets value class.
+     *
+     * @param valCls Value class.
+     */
+    public void valueClass(Class<?> valCls) {
+        this.valCls = valCls;
+    }
+
+    /**
+     * @return Key class.
+     */
+    public Class<?> keyClass() {
+        return keyCls;
+    }
+
+    /**
+     * Set key class.
+     *
+     * @param keyCls Key class.
+     */
+    public void keyClass(Class<?> keyCls) {
+        this.keyCls = keyCls;
+    }
+
+    /**
+     * Adds property to the type descriptor.
+     *
+     * @param prop Property.
+     * @param key Property ownership flag (key or not).
+     * @param failOnDuplicate Fail on duplicate flag.
+     */
+    public void addProperty(QueryEntityClassProperty prop, boolean key, boolean failOnDuplicate) {
+        String name = prop.fullName();
+
+        if (props.put(name, prop) != null && failOnDuplicate)
+            throw new CacheException("Property with name '" + name + "' already exists.");
+
+        fields.put(name, prop.type());
+
+        if (key)
+            keyProps.add(name);
+    }
+
+    /**
+     * @return Class properties.
+     */
+    public Map<String, QueryEntityClassProperty> properties() {
+        return props;
+    }
+
+    /**
+     * @return Properties keys.
+     */
+    public Set<String> keyProperties() {
+        return keyProps;
+    }
+
+    /**
+     * @return {@code true} If we need to have a fulltext index on value.
+     */
+    public boolean valueTextIndex() {
+        return valTextIdx;
+    }
+
+    /**
+     * Sets if this value should be text indexed.
+     *
+     * @param valTextIdx Flag value.
+     */
+    public void valueTextIndex(boolean valTextIdx) {
+        this.valTextIdx = valTextIdx;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(QueryEntityTypeDescriptor.class, this);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/ignite/blob/b093afb8/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/AbstractH2CompareQueryTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/AbstractH2CompareQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/AbstractH2CompareQueryTest.java
index 5475311..1ddd252 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/AbstractH2CompareQueryTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/AbstractH2CompareQueryTest.java
@@ -25,6 +25,7 @@ import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -34,6 +35,7 @@ import org.apache.ignite.IgniteCache;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.CacheMode;
 import org.apache.ignite.cache.CacheWriteSynchronizationMode;
+import org.apache.ignite.cache.QueryEntity;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
@@ -94,7 +96,7 @@ public abstract class AbstractH2CompareQueryTest extends GridCommonAbstractTest
         cc.setCacheMode(mode);
         cc.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
         cc.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
-        cc.setIndexedTypes(clsK, clsV);
+        cc.setQueryEntities(Collections.singleton(new QueryEntity(clsK, clsV)));
 
         return cc;
     }


[05/29] ignite git commit: IGNITE-5126: Batch support for this JDBC driver. This closes #2162.

Posted by nt...@apache.org.
IGNITE-5126: Batch support for this JDBC driver. This closes #2162.


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

Branch: refs/heads/ignite-5947
Commit: 0f22223b7ca25313083e4dc35e7842931a655abd
Parents: 3fdf453
Author: tledkov-gridgain <tl...@gridgain.com>
Authored: Fri Aug 4 11:46:14 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Fri Aug 4 12:04:07 2017 +0300

----------------------------------------------------------------------
 .../jdbc/suite/IgniteJdbcDriverTestSuite.java   |   2 +
 .../ignite/jdbc/thin/JdbcThinBatchSelfTest.java | 333 +++++++++++++++++++
 .../jdbc/thin/JdbcThinPreparedStatement.java    |  16 +-
 .../internal/jdbc/thin/JdbcThinStatement.java   |  46 ++-
 .../internal/jdbc/thin/JdbcThinTcpIo.java       |  20 ++
 .../odbc/jdbc/JdbcBatchExecuteRequest.java      | 109 ++++++
 .../odbc/jdbc/JdbcBatchExecuteResult.java       |  96 ++++++
 .../processors/odbc/jdbc/JdbcQuery.java         |  95 ++++++
 .../processors/odbc/jdbc/JdbcRequest.java       |   8 +
 .../odbc/jdbc/JdbcRequestHandler.java           |  66 +++-
 .../processors/odbc/jdbc/JdbcResult.java        |  11 +
 11 files changed, 794 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
index 8ca3d45..cf7ee8f 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
@@ -33,6 +33,7 @@ import org.apache.ignite.jdbc.JdbcPreparedStatementSelfTest;
 import org.apache.ignite.jdbc.JdbcResultSetSelfTest;
 import org.apache.ignite.jdbc.JdbcStatementSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinAutoCloseServerCursorTest;
+import org.apache.ignite.jdbc.thin.JdbcThinBatchSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinComplexQuerySelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinConnectionSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinDeleteStatementSelfTest;
@@ -121,6 +122,7 @@ public class IgniteJdbcDriverTestSuite extends TestSuite {
         suite.addTest(new TestSuite(JdbcThinMergeStatementSelfTest.class));
         suite.addTest(new TestSuite(JdbcThinDeleteStatementSelfTest.class));
         suite.addTest(new TestSuite(JdbcThinAutoCloseServerCursorTest.class));
+        suite.addTest(new TestSuite(JdbcThinBatchSelfTest.class));
 
         // New thin JDBC driver, DDL tests
         suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedNearSelfTest.class));

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBatchSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBatchSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBatchSelfTest.java
new file mode 100644
index 0000000..5781e00
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinBatchSelfTest.java
@@ -0,0 +1,333 @@
+/*
+ * 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.jdbc.thin;
+
+import java.sql.BatchUpdateException;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.concurrent.Callable;
+import org.apache.ignite.testframework.GridTestUtils;
+
+/**
+ * Statement test.
+ */
+public class JdbcThinBatchSelfTest extends JdbcThinAbstractDmlStatementSelfTest {
+    /** SQL query. */
+    private static final String SQL_PREPARED = "insert into Person(_key, id, firstName, lastName, age) values " +
+        "(?, ?, ?, ?, ?)";
+
+    /** Statement. */
+    private Statement stmt;
+
+    /** Prepared statement. */
+    private PreparedStatement pstmt;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        stmt = conn.createStatement();
+
+        pstmt = conn.prepareStatement(SQL_PREPARED);
+
+        assertNotNull(stmt);
+        assertFalse(stmt.isClosed());
+
+        assertNotNull(pstmt);
+        assertFalse(pstmt.isClosed());
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        if (stmt != null && !stmt.isClosed())
+            stmt.close();
+
+        if (pstmt != null && !pstmt.isClosed())
+            pstmt.close();
+
+        assertTrue(pstmt.isClosed());
+        assertTrue(stmt.isClosed());
+
+        super.afterTest();
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatch() throws SQLException {
+        final int BATCH_SIZE = 10;
+
+        for (int idx = 0, i = 0; i < BATCH_SIZE; ++i, idx += i) {
+            stmt.addBatch("insert into Person (_key, id, firstName, lastName, age) values "
+                + generateValues(idx, i + 1));
+        }
+
+        int [] updCnts = stmt.executeBatch();
+
+        assertEquals("Invalid update counts size", BATCH_SIZE, updCnts.length);
+
+        for (int i = 0; i < BATCH_SIZE; ++i)
+            assertEquals("Invalid update count",i + 1, updCnts[i]);
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatchOnClosedStatement() throws SQLException {
+        final Statement stmt2 = conn.createStatement();
+        final PreparedStatement pstmt2 = conn.prepareStatement("");
+
+        stmt2.close();
+        pstmt2.close();
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                stmt2.addBatch("");
+
+                return null;
+            }
+        }, SQLException.class, "Statement is closed.");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                stmt2.clearBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Statement is closed.");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                stmt2.executeBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Statement is closed.");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                pstmt2.addBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Statement is closed.");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                pstmt2.clearBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Statement is closed.");
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                pstmt2.executeBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Statement is closed.");
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatchException() throws SQLException {
+        final int BATCH_SIZE = 7;
+
+        for (int idx = 0, i = 0; i < BATCH_SIZE; ++i, idx += i) {
+            stmt.addBatch("insert into Person (_key, id, firstName, lastName, age) values "
+                + generateValues(idx, i + 1));
+        }
+
+        stmt.addBatch("select * from Person");
+
+        stmt.addBatch("insert into Person (_key, id, firstName, lastName, age) values "
+            + generateValues(100, 1));
+
+        try {
+            stmt.executeBatch();
+
+            fail("BatchUpdateException must be thrown");
+        } catch(BatchUpdateException e) {
+            int [] updCnts = e.getUpdateCounts();
+
+            assertEquals("Invalid update counts size", BATCH_SIZE, updCnts.length);
+
+            for (int i = 0; i < BATCH_SIZE; ++i)
+                assertEquals("Invalid update count",i + 1, updCnts[i]);
+
+            if (!e.getMessage().contains("Query produced result set [qry=select * from Person, args=[]]")) {
+                log.error("Invalid exception: ", e);
+
+                fail();
+            }
+        }
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatchClear() throws SQLException {
+        final int BATCH_SIZE = 7;
+
+        for (int idx = 0, i = 0; i < BATCH_SIZE; ++i, idx += i) {
+            stmt.addBatch("insert into Person (_key, id, firstName, lastName, age) values "
+                + generateValues(idx, i + 1));
+        }
+
+        stmt.clearBatch();
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                stmt.executeBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Batch is empty.");
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatchPrepared() throws SQLException {
+        final int BATCH_SIZE = 10;
+
+        for (int i = 0; i < BATCH_SIZE; ++i) {
+            int paramCnt = 1;
+
+            pstmt.setString(paramCnt++, "p" + i);
+            pstmt.setInt(paramCnt++, i);
+            pstmt.setString(paramCnt++, "Name" + i);
+            pstmt.setString(paramCnt++, "Lastname" + i);
+            pstmt.setInt(paramCnt++, 20 + i);
+
+            pstmt.addBatch();
+        }
+
+        int [] updCnts = pstmt.executeBatch();
+
+        assertEquals("Invalid update counts size", BATCH_SIZE, updCnts.length);
+
+        for (int i = 0; i < BATCH_SIZE; ++i)
+            assertEquals("Invalid update count",1, updCnts[i]);
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatchExceptionPrepared() throws SQLException {
+        final int BATCH_SIZE = 7;
+
+        for (int i = 0; i < BATCH_SIZE; ++i) {
+            int paramCnt = 1;
+
+            pstmt.setString(paramCnt++, "p" + i);
+            pstmt.setInt(paramCnt++, i);
+            pstmt.setString(paramCnt++, "Name" + i);
+            pstmt.setString(paramCnt++, "Lastname" + i);
+            pstmt.setInt(paramCnt++, 20 + i);
+
+            pstmt.addBatch();
+        }
+
+        int paramCnt = 1;
+        pstmt.setString(paramCnt++, "p" + 100);
+        pstmt.setString(paramCnt++, "x");
+        pstmt.setString(paramCnt++, "Name" + 100);
+        pstmt.setString(paramCnt++, "Lastname" + 100);
+        pstmt.setInt(paramCnt++, 20 + 100);
+
+        pstmt.addBatch();
+
+        try {
+            pstmt.executeBatch();
+
+            fail("BatchUpdateException must be thrown");
+        } catch(BatchUpdateException e) {
+            int [] updCnts = e.getUpdateCounts();
+
+            assertEquals("Invalid update counts size", BATCH_SIZE, updCnts.length);
+
+            for (int i = 0; i < BATCH_SIZE; ++i)
+                assertEquals("Invalid update count",1, updCnts[i]);
+
+            if (!e.getMessage().contains("Failed to execute SQL query.")) {
+                log.error("Invalid exception: ", e);
+
+                fail();
+            }
+        }
+    }
+
+    /**
+     * @throws SQLException If failed.
+     */
+    public void testBatchClearPrepared() throws SQLException {
+        final int BATCH_SIZE = 10;
+
+        for (int i = 0; i < BATCH_SIZE; ++i) {
+            int paramCnt = 1;
+
+            pstmt.setString(paramCnt++, "p" + i);
+            pstmt.setInt(paramCnt++, i);
+            pstmt.setString(paramCnt++, "Name" + i);
+            pstmt.setString(paramCnt++, "Lastname" + i);
+            pstmt.setInt(paramCnt++, 20 + i);
+
+            pstmt.addBatch();
+        }
+
+        pstmt.clearBatch();
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                pstmt.executeBatch();
+
+                return null;
+            }
+        }, SQLException.class, "Batch is empty.");
+    }
+
+    /**
+     * @param beginIndex Begin row index.
+     * @param cnt Count of rows.
+     * @return String contains values for 'cnt' rows.
+     */
+    private String generateValues(int beginIndex, int cnt) {
+        StringBuilder sb = new StringBuilder();
+
+        int lastIdx = beginIndex + cnt - 1;
+
+        for (int i = beginIndex; i < lastIdx; ++i)
+            sb.append(valuesRow(i)).append(',');
+
+        sb.append(valuesRow(lastIdx));
+
+        return sb.toString();
+    }
+
+    /**
+     * @param idx Index of the row.
+     * @return String with row values.
+     */
+    private String valuesRow(int idx) {
+        return String.format("('p%d', %d, 'Name%d', 'Lastname%d', %d)", idx, idx, idx, idx, 20 + idx);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java
index 0c78a13..455c80f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java
@@ -40,6 +40,7 @@ import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Calendar;
 import org.apache.ignite.internal.processors.odbc.SqlListenerUtils;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery;
 
 /**
  * JDBC prepared statement implementation.
@@ -230,7 +231,20 @@ public class JdbcThinPreparedStatement extends JdbcThinStatement implements Prep
     @Override public void addBatch() throws SQLException {
         ensureNotClosed();
 
-        throw new SQLFeatureNotSupportedException("Updates are not supported.");
+        if (batch == null) {
+            batch = new ArrayList<>();
+
+            batch.add(new JdbcQuery(sql, args.toArray(new Object[args.size()])));
+        }
+        else
+            batch.add(new JdbcQuery(null, args.toArray(new Object[args.size()])));
+
+        args = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void addBatch(String sql) throws SQLException {
+        throw new SQLException("The method 'addBatch(String)' is called on PreparedStatement instance.");
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
index 2cad223..b01350a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
@@ -18,15 +18,20 @@
 package org.apache.ignite.internal.jdbc.thin;
 
 import java.io.IOException;
+import java.sql.BatchUpdateException;
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.SQLWarning;
 import java.sql.Statement;
+import java.util.ArrayList;
 import java.util.List;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.internal.processors.odbc.SqlListenerResponse;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteResult;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult;
 
 import static java.sql.ResultSet.CONCUR_READ_ONLY;
@@ -62,6 +67,9 @@ public class JdbcThinStatement implements Statement {
     /** */
     private boolean alreadyRead;
 
+    /** Batch. */
+    protected List<JdbcQuery> batch;
+
     /**
      * Creates new statement.
      *
@@ -323,21 +331,53 @@ public class JdbcThinStatement implements Statement {
     @Override public void addBatch(String sql) throws SQLException {
         ensureNotClosed();
 
-        throw new SQLFeatureNotSupportedException("Updates are not supported.");
+        if (batch == null)
+            batch = new ArrayList<>();
+
+        batch.add(new JdbcQuery(sql, null));
     }
 
     /** {@inheritDoc} */
     @Override public void clearBatch() throws SQLException {
         ensureNotClosed();
 
-        throw new SQLFeatureNotSupportedException("Updates are not supported.");
+        batch = null;
     }
 
     /** {@inheritDoc} */
     @Override public int[] executeBatch() throws SQLException {
         ensureNotClosed();
 
-        throw new SQLFeatureNotSupportedException("Updates are not supported.");
+        if (rs != null) {
+            rs.close();
+
+            rs = null;
+        }
+
+        alreadyRead = false;
+
+        if (batch == null || batch.isEmpty())
+            throw new SQLException("Batch is empty.");
+
+        try {
+            JdbcBatchExecuteResult res = conn.io().batchExecute(conn.getSchema(), batch);
+
+            if (res.errorCode() != SqlListenerResponse.STATUS_SUCCESS)
+                throw new BatchUpdateException(res.errorMessage(), null, res.errorCode(), res.updateCounts());
+
+            return res.updateCounts();
+        }
+        catch (IOException e) {
+            conn.close();
+
+            throw new SQLException("Failed to query Ignite.", e);
+        }
+        catch (IgniteCheckedException e) {
+            throw new SQLException("Failed to query Ignite.", e);
+        }
+        finally {
+            batch = null;
+        }
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
index be62a8d..f54d5fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
@@ -32,6 +32,9 @@ import org.apache.ignite.internal.processors.odbc.SqlListenerNioListener;
 import org.apache.ignite.internal.processors.odbc.SqlListenerProtocolVersion;
 import org.apache.ignite.internal.processors.odbc.SqlListenerRequest;
 import org.apache.ignite.internal.processors.odbc.SqlListenerResponse;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteRequest;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteResult;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryCloseRequest;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteRequest;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult;
@@ -58,6 +61,9 @@ public class JdbcThinTcpIo {
     /** Initial output for query message. */
     private static final int QUERY_EXEC_MSG_INIT_CAP = 256;
 
+    /** Maximum batch query count. */
+    private static final int MAX_BATCH_QRY_CNT = 32;
+
     /** Initial output for query fetch message. */
     private static final int QUERY_FETCH_MSG_SIZE = 13;
 
@@ -289,6 +295,20 @@ public class JdbcThinTcpIo {
     }
 
     /**
+     * @param schema Schema.
+     * @param batch Batch queries.
+     * @return Result.
+     * @throws IOException On error.
+     * @throws IgniteCheckedException On error.
+     */
+    public JdbcBatchExecuteResult batchExecute(String schema, List<JdbcQuery> batch)
+        throws IOException, IgniteCheckedException {
+        int cnt = Math.min(MAX_BATCH_QRY_CNT, batch.size());
+
+        return sendRequest(new JdbcBatchExecuteRequest(schema, batch), QUERY_EXEC_MSG_INIT_CAP * cnt);
+    }
+
+    /**
      * @param req ODBC request.
      * @throws IOException On error.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java
new file mode 100644
index 0000000..9f71bff
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteRequest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.jdbc;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.internal.binary.BinaryReaderExImpl;
+import org.apache.ignite.internal.binary.BinaryWriterExImpl;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * JDBC batch execute request.
+ */
+public class JdbcBatchExecuteRequest extends JdbcRequest {
+    /** Cache name. */
+    private String schema;
+
+    /** Sql query. */
+    @GridToStringInclude(sensitive = true)
+    private List<JdbcQuery> queries;
+
+    /**
+     * Default constructor.
+     */
+    public JdbcBatchExecuteRequest() {
+        super(BATCH_EXEC);
+    }
+
+    /**
+     * @param schema Schema.
+     * @param queries Queries.
+     */
+    public JdbcBatchExecuteRequest(String schema, List<JdbcQuery> queries) {
+        super(BATCH_EXEC);
+
+        assert !F.isEmpty(queries);
+
+        this.schema = schema;
+        this.queries = queries;
+    }
+
+    /**
+     * @return Schema.
+     */
+    @Nullable public String schema() {
+        return schema;
+    }
+
+    /**
+     * @return Queries.
+     */
+    public List<JdbcQuery> queries() {
+        return queries;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeBinary(BinaryWriterExImpl writer) throws BinaryObjectException {
+        super.writeBinary(writer);
+
+        writer.writeString(schema);
+        writer.writeInt(queries.size());
+
+        for (JdbcQuery q : queries)
+            q.writeBinary(writer);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readBinary(BinaryReaderExImpl reader) throws BinaryObjectException {
+        super.readBinary(reader);
+
+        schema = reader.readString();
+
+        int n = reader.readInt();
+
+        queries = new ArrayList<>(n);
+
+        for (int i = 0; i < n; ++i) {
+            JdbcQuery qry = new JdbcQuery();
+
+            qry.readBinary(reader);
+
+            queries.add(qry);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(JdbcBatchExecuteRequest.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java
new file mode 100644
index 0000000..7977c22
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcBatchExecuteResult.java
@@ -0,0 +1,96 @@
+/*
+ * 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.jdbc;
+
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.internal.binary.BinaryReaderExImpl;
+import org.apache.ignite.internal.binary.BinaryWriterExImpl;
+
+/**
+ * JDBC batch execute result.
+ */
+public class JdbcBatchExecuteResult extends JdbcResult {
+    /** Update counts. */
+    private int [] updateCnts;
+
+    /** Batch update error code. */
+    private int errCode;
+
+    /** Batch update error message. */
+    private String errMsg;
+
+    /**
+     * Condtructor.
+     */
+    public JdbcBatchExecuteResult() {
+        super(BATCH_EXEC);
+    }
+
+    /**
+     * @param updateCnts Update counts for batch.
+     * @param errCode Error code.
+     * @param errMsg Error message.
+     */
+    public JdbcBatchExecuteResult(int [] updateCnts, int errCode, String errMsg) {
+        super(BATCH_EXEC);
+
+        this.updateCnts = updateCnts;
+        this.errCode = errCode;
+        this.errMsg = errMsg;
+    }
+
+    /**
+     * @return Update count for DML queries.
+     */
+    public int[] updateCounts() {
+        return updateCnts;
+    }
+
+    /**
+     * @return Batch error code.
+     */
+    public int errorCode() {
+        return errCode;
+    }
+
+    /**
+     * @return Batch error message.
+     */
+    public String errorMessage() {
+        return errMsg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeBinary(BinaryWriterExImpl writer) throws BinaryObjectException {
+        super.writeBinary(writer);
+
+        writer.writeInt(errCode);
+        writer.writeString(errMsg);
+        writer.writeIntArray(updateCnts);
+    }
+
+
+    /** {@inheritDoc} */
+    @Override public void readBinary(BinaryReaderExImpl reader) throws BinaryObjectException {
+        super.readBinary(reader);
+
+        errCode = reader.readInt();
+        errMsg = reader.readString();
+        updateCnts = reader.readIntArray();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQuery.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQuery.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQuery.java
new file mode 100644
index 0000000..f7ffb99
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQuery.java
@@ -0,0 +1,95 @@
+/*
+ * 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.jdbc;
+
+import org.apache.ignite.internal.binary.BinaryReaderExImpl;
+import org.apache.ignite.internal.binary.BinaryWriterExImpl;
+import org.apache.ignite.internal.processors.odbc.SqlListenerUtils;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ * JDBC SQL query with parameters.
+ */
+public class JdbcQuery implements JdbcRawBinarylizable {
+    /** Query SQL. */
+    private String sql;
+
+    /** Arguments. */
+    private Object[] args;
+
+    /**
+     * Default constructor is used for serialization.
+     */
+    public JdbcQuery() {
+        // No-op.
+    }
+
+    /**
+     * @param sql Query SQL.
+     * @param args Arguments.
+     */
+    public JdbcQuery(String sql, Object[] args) {
+        this.sql = sql;
+        this.args = args;
+    }
+
+    /**
+     * @return Query SQL string.
+     */
+    public String sql() {
+        return sql;
+    }
+
+    /**
+     * @return Query arguments.
+     */
+    public Object[] args() {
+        return args;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeBinary(BinaryWriterExImpl writer) {
+        writer.writeString(sql);
+
+        if (args == null || args.length == 0)
+            writer.writeInt(0);
+        else {
+            writer.writeInt(args.length);
+
+            for (Object arg : args)
+                SqlListenerUtils.writeObject(writer, arg, false);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readBinary(BinaryReaderExImpl reader) {
+        sql = reader.readString();
+
+        int argsNum = reader.readInt();
+
+        args = new Object[argsNum];
+
+        for (int i = 0; i < argsNum; ++i)
+            args[i] = SqlListenerUtils.readObject(reader, false);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(JdbcQuery.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
index d6f8fd3..0e144cc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequest.java
@@ -39,6 +39,9 @@ public class JdbcRequest extends SqlListenerRequest implements JdbcRawBinaryliza
     /** Get columns meta query. */
     public static final byte QRY_META = 5;
 
+    /** Batch queries. */
+    public static final byte BATCH_EXEC = 6;
+
     /** Request type. */
     private byte type;
 
@@ -97,6 +100,11 @@ public class JdbcRequest extends SqlListenerRequest implements JdbcRawBinaryliza
 
                 break;
 
+            case BATCH_EXEC:
+                req = new JdbcBatchExecuteRequest();
+
+                break;
+
             default:
                 throw new IgniteException("Unknown SQL listener request ID: [request ID=" + reqType + ']');
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
index 94ac433..60c08f9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
@@ -17,6 +17,11 @@
 
 package org.apache.ignite.internal.processors.odbc.jdbc;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cache.query.FieldsQueryCursor;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
@@ -31,10 +36,7 @@ import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
+import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.BATCH_EXEC;
 import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.QRY_CLOSE;
 import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.QRY_EXEC;
 import static org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest.QRY_FETCH;
@@ -129,6 +131,9 @@ public class JdbcRequestHandler implements SqlListenerRequestHandler {
 
                 case QRY_META:
                     return getQueryMeta((JdbcQueryMetadataRequest)req);
+
+                case BATCH_EXEC:
+                    return executeBatch((JdbcBatchExecuteRequest)req);
             }
 
             return new JdbcResponse(SqlListenerResponse.STATUS_FAILED, "Unsupported JDBC request [req=" + req + ']');
@@ -307,4 +312,57 @@ public class JdbcRequestHandler implements SqlListenerRequestHandler {
             return new JdbcResponse(SqlListenerResponse.STATUS_FAILED, e.toString());
         }
     }
+
+    /**
+     * @param req Request.
+     * @return Response.
+     */
+    private SqlListenerResponse executeBatch(JdbcBatchExecuteRequest req) {
+        String schemaName = req.schema();
+
+        if (F.isEmpty(schemaName))
+            schemaName = QueryUtils.DFLT_SCHEMA;
+
+        int successQueries = 0;
+        int updCnts[] = new int[req.queries().size()];
+
+        try {
+            String sql = null;
+
+            for (JdbcQuery q : req.queries()) {
+                if (q.sql() != null)
+                    sql = q.sql();
+
+                SqlFieldsQuery qry = new SqlFieldsQuery(sql);
+
+                qry.setArgs(q.args());
+
+                qry.setDistributedJoins(distributedJoins);
+                qry.setEnforceJoinOrder(enforceJoinOrder);
+                qry.setCollocated(collocated);
+                qry.setReplicatedOnly(replicatedOnly);
+
+                qry.setSchema(schemaName);
+
+                QueryCursorImpl<List<?>> qryCur = (QueryCursorImpl<List<?>>)ctx.query()
+                    .querySqlFieldsNoCache(qry, true);
+
+                if (qryCur.isQuery())
+                    throw new IgniteCheckedException("Query produced result set [qry=" + q.sql() + ", args=" +
+                        Arrays.toString(q.args()) + ']');
+
+                List<List<?>> items = qryCur.getAll();
+
+                updCnts[successQueries++] = ((Long)items.get(0).get(0)).intValue();
+            }
+
+            return new JdbcResponse(new JdbcBatchExecuteResult(updCnts, SqlListenerResponse.STATUS_SUCCESS, null));
+        }
+        catch (Exception e) {
+            U.error(log, "Failed to execute batch query [reqId=" + req.requestId() + ", req=" + req + ']', e);
+
+            return new JdbcResponse(new JdbcBatchExecuteResult(Arrays.copyOf(updCnts, successQueries),
+                SqlListenerResponse.STATUS_FAILED, e.toString()));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/0f22223b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
index 2d7666e..48affe9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java
@@ -35,6 +35,9 @@ public class JdbcResult implements JdbcRawBinarylizable {
     /** Get columns meta query result. */
     public static final byte QRY_META = 4;
 
+    /** Batch queries. */
+    public static final byte BATCH_EXEC = 6;
+
     /** Success status. */
     private byte type;
 
@@ -70,14 +73,22 @@ public class JdbcResult implements JdbcRawBinarylizable {
         switch(resId) {
             case QRY_EXEC:
                 res = new JdbcQueryExecuteResult();
+
                 break;
 
             case QRY_FETCH:
                 res = new JdbcQueryFetchResult();
+
                 break;
 
             case QRY_META:
                 res = new JdbcQueryMetadataResult();
+
+                break;
+
+            case BATCH_EXEC:
+                res = new JdbcBatchExecuteResult();
+
                 break;
 
             default:


[11/29] ignite git commit: IGNITE-5982: GridMapQueryExecutor was split into several pieces.

Posted by nt...@apache.org.
IGNITE-5982: GridMapQueryExecutor was split into several pieces.


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

Branch: refs/heads/ignite-5947
Commit: 879f19106b22e66d5f6ea94424d961d049397410
Parents: b093afb
Author: devozerov <vo...@gridgain.com>
Authored: Tue Aug 8 15:16:58 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Tue Aug 8 15:17:58 2017 +0300

----------------------------------------------------------------------
 .../query/h2/twostep/GridMapQueryExecutor.java  | 501 ++-----------------
 .../query/h2/twostep/MapNodeResults.java        | 108 ++++
 .../query/h2/twostep/MapQueryResult.java        | 258 ++++++++++
 .../query/h2/twostep/MapQueryResults.java       | 155 ++++++
 .../h2/twostep/MapReplicatedReservation.java    |  38 ++
 .../query/h2/twostep/MapRequestKey.java         |  65 +++
 .../query/h2/twostep/MapReservationKey.java     |  73 +++
 7 files changed, 730 insertions(+), 468 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
index fcf5f10..19b628b 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.processors.query.h2.twostep;
 
-import java.lang.reflect.Field;
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.util.AbstractCollection;
@@ -31,7 +30,6 @@ import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicReferenceArray;
 import javax.cache.CacheException;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteException;
@@ -39,7 +37,6 @@ import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cache.query.QueryCancelledException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.events.CacheQueryExecutedEvent;
-import org.apache.ignite.events.CacheQueryReadEvent;
 import org.apache.ignite.events.DiscoveryEvent;
 import org.apache.ignite.events.Event;
 import org.apache.ignite.events.EventType;
@@ -57,35 +54,29 @@ import org.apache.ignite.internal.processors.cache.query.CacheQueryType;
 import org.apache.ignite.internal.processors.cache.query.GridCacheQueryMarshallable;
 import org.apache.ignite.internal.processors.cache.query.GridCacheSqlQuery;
 import org.apache.ignite.internal.processors.cache.query.QueryTable;
-import org.apache.ignite.internal.processors.query.GridQueryCancel;
 import org.apache.ignite.internal.processors.query.h2.H2Utils;
 import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
 import org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryContext;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2RetryException;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
-import org.apache.ignite.internal.processors.query.h2.opt.GridH2ValueCacheObject;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryCancelRequest;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryFailResponse;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryNextPageRequest;
 import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryNextPageResponse;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2QueryRequest;
-import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
 import org.apache.ignite.internal.util.typedef.CI1;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.h2.jdbc.JdbcResultSet;
-import org.h2.result.ResultInterface;
 import org.h2.value.Value;
 import org.jetbrains.annotations.Nullable;
 import org.jsr166.ConcurrentHashMap8;
 
 import static org.apache.ignite.events.EventType.EVT_CACHE_QUERY_EXECUTED;
-import static org.apache.ignite.events.EventType.EVT_CACHE_QUERY_OBJECT_READ;
 import static org.apache.ignite.internal.managers.communication.GridIoPolicy.QUERY_POOL;
 import static org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion.NONE;
 import static org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState.OWNING;
@@ -94,30 +85,13 @@ import static org.apache.ignite.internal.processors.query.h2.opt.DistributedJoin
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryType.MAP;
 import static org.apache.ignite.internal.processors.query.h2.opt.GridH2QueryType.REPLICATED;
 import static org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2ValueMessageFactory.toMessages;
-import static org.jsr166.ConcurrentLinkedHashMap.QueuePolicy.PER_SEGMENT_Q;
 
 /**
  * Map query executor.
  */
+@SuppressWarnings("ForLoopReplaceableByForEach")
 public class GridMapQueryExecutor {
     /** */
-    private static final Field RESULT_FIELD;
-
-    /*
-     * Initialize.
-     */
-    static {
-        try {
-            RESULT_FIELD = JdbcResultSet.class.getDeclaredField("result");
-
-            RESULT_FIELD.setAccessible(true);
-        }
-        catch (NoSuchFieldException e) {
-            throw new IllegalStateException("Check H2 version in classpath.", e);
-        }
-    }
-
-    /** */
     private IgniteLogger log;
 
     /** */
@@ -127,14 +101,13 @@ public class GridMapQueryExecutor {
     private IgniteH2Indexing h2;
 
     /** */
-    private ConcurrentMap<UUID, NodeResults> qryRess = new ConcurrentHashMap8<>();
+    private ConcurrentMap<UUID, MapNodeResults> qryRess = new ConcurrentHashMap8<>();
 
     /** */
     private final GridSpinBusyLock busyLock;
 
     /** */
-    private final ConcurrentMap<T2<String, AffinityTopologyVersion>, GridReservable> reservations =
-        new ConcurrentHashMap8<>();
+    private final ConcurrentMap<MapReservationKey, GridReservable> reservations = new ConcurrentHashMap8<>();
 
     /**
      * @param busyLock Busy lock.
@@ -162,7 +135,7 @@ public class GridMapQueryExecutor {
 
                 GridH2QueryContext.clearAfterDeadNode(locNodeId, nodeId);
 
-                NodeResults nodeRess = qryRess.remove(nodeId);
+                MapNodeResults nodeRess = qryRess.remove(nodeId);
 
                 if (nodeRess == null)
                     return;
@@ -172,6 +145,7 @@ public class GridMapQueryExecutor {
         }, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT);
 
         ctx.io().addMessageListener(GridTopic.TOPIC_QUERY, new GridMessageListener() {
+            @SuppressWarnings("deprecation")
             @Override public void onMessage(UUID nodeId, Object msg, byte plc) {
                 if (!busyLock.enterBusy())
                     return;
@@ -228,7 +202,7 @@ public class GridMapQueryExecutor {
     private void onCancel(ClusterNode node, GridQueryCancelRequest msg) {
         long qryReqId = msg.queryRequestId();
 
-        NodeResults nodeRess = resultsForNode(node.id());
+        MapNodeResults nodeRess = resultsForNode(node.id());
 
         boolean clear = GridH2QueryContext.clear(ctx.localNodeId(), node.id(), qryReqId, MAP);
 
@@ -245,13 +219,13 @@ public class GridMapQueryExecutor {
      * @param nodeId Node ID.
      * @return Results for node.
      */
-    private NodeResults resultsForNode(UUID nodeId) {
-        NodeResults nodeRess = qryRess.get(nodeId);
+    private MapNodeResults resultsForNode(UUID nodeId) {
+        MapNodeResults nodeRess = qryRess.get(nodeId);
 
         if (nodeRess == null) {
-            nodeRess = new NodeResults();
+            nodeRess = new MapNodeResults();
 
-            NodeResults old = qryRess.putIfAbsent(nodeId, nodeRess);
+            MapNodeResults old = qryRess.putIfAbsent(nodeId, nodeRess);
 
             if (old != null)
                 nodeRess = old;
@@ -300,13 +274,12 @@ public class GridMapQueryExecutor {
                 continue;
 
             // For replicated cache topology version does not make sense.
-            final T2<String,AffinityTopologyVersion> grpKey =
-                new T2<>(cctx.name(), cctx.isReplicated() ? null : topVer);
+            final MapReservationKey grpKey = new MapReservationKey(cctx.name(), cctx.isReplicated() ? null : topVer);
 
             GridReservable r = reservations.get(grpKey);
 
             if (explicitParts == null && r != null) { // Try to reserve group partition if any and no explicits.
-                if (r != ReplicatedReservation.INSTANCE) {
+                if (r != MapReplicatedReservation.INSTANCE) {
                     if (!r.reserve())
                         return false; // We need explicit partitions here -> retry.
 
@@ -327,7 +300,7 @@ public class GridMapQueryExecutor {
                         }
 
                         // Mark that we checked this replicated cache.
-                        reservations.putIfAbsent(grpKey, ReplicatedReservation.INSTANCE);
+                        reservations.putIfAbsent(grpKey, MapReplicatedReservation.INSTANCE);
                     }
                 }
                 else { // Reserve primary partitions for partitioned cache (if no explicit given).
@@ -381,6 +354,7 @@ public class GridMapQueryExecutor {
             return Collections.emptySet();
 
         return new AbstractCollection<Integer>() {
+            @SuppressWarnings("NullableProblems")
             @Override public Iterator<Integer> iterator() {
                 return new Iterator<Integer>() {
                     /** */
@@ -537,9 +511,9 @@ public class GridMapQueryExecutor {
         GridCacheContext<?, ?> mainCctx =
             !F.isEmpty(cacheIds) ? ctx.cache().context().cacheContext(cacheIds.get(0)) : null;
 
-        NodeResults nodeRess = resultsForNode(node.id());
+        MapNodeResults nodeRess = resultsForNode(node.id());
 
-        QueryResults qr = null;
+        MapQueryResults qr = null;
 
         List<GridReservable> reserved = new ArrayList<>();
 
@@ -553,7 +527,7 @@ public class GridMapQueryExecutor {
                 }
             }
 
-            qr = new QueryResults(reqId, qrys.size(), mainCctx != null ? mainCctx.name() : null);
+            qr = new MapQueryResults(h2, reqId, qrys.size(), mainCctx != null ? mainCctx.name() : null);
 
             if (nodeRess.put(reqId, segmentId, qr) != null)
                 throw new IllegalStateException();
@@ -619,7 +593,7 @@ public class GridMapQueryExecutor {
                         rs = h2.executeSqlQueryWithTimer(conn, qry.query(),
                             F.asList(qry.parameters(params)), true,
                             timeout,
-                            qr.cancels[qryIdx]);
+                            qr.queryCancel(qryIdx));
 
                         if (evt) {
                             assert mainCctx != null;
@@ -644,7 +618,7 @@ public class GridMapQueryExecutor {
 
                     qr.addResult(qryIdx, qry, node.id(), rs, params);
 
-                    if (qr.canceled) {
+                    if (qr.cancelled()) {
                         qr.result(qryIdx).close();
 
                         throw new QueryCancelledException();
@@ -724,7 +698,7 @@ public class GridMapQueryExecutor {
      * @param req Request.
      */
     private void onNextPageRequest(ClusterNode node, GridQueryNextPageRequest req) {
-        NodeResults nodeRess = qryRess.get(node.id());
+        MapNodeResults nodeRess = qryRess.get(node.id());
 
         if (nodeRess == null) {
             sendError(node, req.queryRequestId(), new CacheException("No node result found for request: " + req));
@@ -736,11 +710,11 @@ public class GridMapQueryExecutor {
             return;
         }
 
-        QueryResults qr = nodeRess.get(req.queryRequestId(), req.segmentId());
+        MapQueryResults qr = nodeRess.get(req.queryRequestId(), req.segmentId());
 
         if (qr == null)
             sendError(node, req.queryRequestId(), new CacheException("No query result found for request: " + req));
-        else if (qr.canceled)
+        else if (qr.cancelled())
             sendError(node, req.queryRequestId(), new QueryCancelledException());
         else
             sendNextPage(nodeRess, node, qr, req.query(), req.segmentId(), req.pageSize());
@@ -754,16 +728,16 @@ public class GridMapQueryExecutor {
      * @param segmentId Index segment ID.
      * @param pageSize Page size.
      */
-    private void sendNextPage(NodeResults nodeRess, ClusterNode node, QueryResults qr, int qry, int segmentId,
+    private void sendNextPage(MapNodeResults nodeRess, ClusterNode node, MapQueryResults qr, int qry, int segmentId,
         int pageSize) {
-        QueryResult res = qr.result(qry);
+        MapQueryResult res = qr.result(qry);
 
         assert res != null;
 
-        if (res.closed)
+        if (res.closed())
             return;
 
-        int page = res.page;
+        int page = res.page();
 
         List<Value[]> rows = new ArrayList<>(Math.min(64, pageSize));
 
@@ -773,16 +747,16 @@ public class GridMapQueryExecutor {
             res.close();
 
             if (qr.isAllClosed())
-                nodeRess.remove(qr.qryReqId, segmentId, qr);
+                nodeRess.remove(qr.queryRequestId(), segmentId, qr);
         }
 
         try {
             boolean loc = node.isLocal();
 
-            GridQueryNextPageResponse msg = new GridQueryNextPageResponse(qr.qryReqId, segmentId, qry, page,
-                page == 0 ? res.rowCnt : -1,
-                res.cols,
-                loc ? null : toMessages(rows, new ArrayList<Message>(res.cols)),
+            GridQueryNextPageResponse msg = new GridQueryNextPageResponse(qr.queryRequestId(), segmentId, qry, page,
+                page == 0 ? res.rowCount() : -1,
+                res.columnCount(),
+                loc ? null : toMessages(rows, new ArrayList<Message>(res.columnCount())),
                 loc ? rows : null);
 
             if (loc)
@@ -828,418 +802,9 @@ public class GridMapQueryExecutor {
      */
     public void onCacheStop(String cacheName) {
         // Drop group reservations.
-        for (T2<String,AffinityTopologyVersion> grpKey : reservations.keySet()) {
-            if (F.eq(grpKey.get1(), cacheName))
+        for (MapReservationKey grpKey : reservations.keySet()) {
+            if (F.eq(grpKey.cacheName(), cacheName))
                 reservations.remove(grpKey);
         }
     }
-
-
-    /**
-     *
-     */
-    private static class NodeResults {
-        /** */
-        private final ConcurrentMap<RequestKey, QueryResults> res = new ConcurrentHashMap8<>();
-
-        /** */
-        private final GridBoundedConcurrentLinkedHashMap<Long, Boolean> qryHist =
-            new GridBoundedConcurrentLinkedHashMap<>(1024, 1024, 0.75f, 64, PER_SEGMENT_Q);
-
-        /**
-         * @param reqId Query Request ID.
-         * @return {@code False} if query was already cancelled.
-         */
-        boolean cancelled(long reqId) {
-            return qryHist.get(reqId) != null;
-        }
-
-        /**
-         * @param reqId Query Request ID.
-         * @return {@code True} if cancelled.
-         */
-        boolean onCancel(long reqId) {
-            Boolean old = qryHist.putIfAbsent(reqId, Boolean.FALSE);
-
-            return old == null;
-        }
-
-        /**
-         * @param reqId Query Request ID.
-         * @param segmentId Index segment ID.
-         * @return query partial results.
-         */
-        public QueryResults get(long reqId, int segmentId) {
-            return res.get(new RequestKey(reqId, segmentId));
-        }
-
-        /**
-         * Cancel all thread of given request.
-         * @param reqID Request ID.
-         */
-        public void cancelRequest(long reqID) {
-            for (RequestKey key : res.keySet()) {
-                if (key.reqId == reqID) {
-                    QueryResults removed = res.remove(key);
-
-                    if (removed != null)
-                        removed.cancel(true);
-                }
-
-            }
-        }
-
-        /**
-         * @param reqId Query Request ID.
-         * @param segmentId Index segment ID.
-         * @param qr Query Results.
-         * @return {@code True} if removed.
-         */
-        public boolean remove(long reqId, int segmentId, QueryResults qr) {
-            return res.remove(new RequestKey(reqId, segmentId), qr);
-        }
-
-        /**
-         * @param reqId Query Request ID.
-         * @param segmentId Index segment ID.
-         * @param qr Query Results.
-         * @return previous value.
-         */
-        public QueryResults put(long reqId, int segmentId, QueryResults qr) {
-            return res.put(new RequestKey(reqId, segmentId), qr);
-        }
-
-        /**
-         * Cancel all node queries.
-         */
-        public void cancelAll() {
-            for (QueryResults ress : res.values())
-                ress.cancel(true);
-        }
-
-        /**
-         *
-         */
-        private static class RequestKey {
-            /** */
-            private long reqId;
-
-            /** */
-            private int segmentId;
-
-            /** Constructor */
-            RequestKey(long reqId, int segmentId) {
-                this.reqId = reqId;
-                this.segmentId = segmentId;
-            }
-
-            /** {@inheritDoc} */
-            @Override public boolean equals(Object o) {
-                if (this == o)
-                    return true;
-                if (o == null || getClass() != o.getClass())
-                    return false;
-
-                RequestKey other = (RequestKey)o;
-
-                return reqId == other.reqId && segmentId == other.segmentId;
-
-            }
-
-            /** {@inheritDoc} */
-            @Override public int hashCode() {
-                int result = (int)(reqId ^ (reqId >>> 32));
-                result = 31 * result + segmentId;
-                return result;
-            }
-        }
-    }
-
-    /**
-     *
-     */
-    private class QueryResults {
-        /** */
-        private final long qryReqId;
-
-        /** */
-        private final AtomicReferenceArray<QueryResult> results;
-
-        /** */
-        private final GridQueryCancel[] cancels;
-
-        /** */
-        private final String cacheName;
-
-        /** */
-        private volatile boolean canceled;
-
-        /**
-         * @param qryReqId Query request ID.
-         * @param qrys Number of queries.
-         * @param cacheName Cache name.
-         */
-        @SuppressWarnings("unchecked")
-        private QueryResults(long qryReqId, int qrys, @Nullable String cacheName) {
-            this.qryReqId = qryReqId;
-            this.cacheName = cacheName;
-
-            results = new AtomicReferenceArray<>(qrys);
-            cancels = new GridQueryCancel[qrys];
-
-            for (int i = 0; i < cancels.length; i++)
-                cancels[i] = new GridQueryCancel();
-        }
-
-        /**
-         * @param qry Query result index.
-         * @return Query result.
-         */
-        QueryResult result(int qry) {
-            return results.get(qry);
-        }
-
-        /**
-         * @param qry Query result index.
-         * @param q Query object.
-         * @param qrySrcNodeId Query source node.
-         * @param rs Result set.
-         */
-        void addResult(int qry, GridCacheSqlQuery q, UUID qrySrcNodeId, ResultSet rs, Object[] params) {
-            if (!results.compareAndSet(qry, null, new QueryResult(rs, ctx, cacheName, qrySrcNodeId, q, params)))
-                throw new IllegalStateException();
-        }
-
-        /**
-         * @return {@code true} If all results are closed.
-         */
-        boolean isAllClosed() {
-            for (int i = 0; i < results.length(); i++) {
-                QueryResult res = results.get(i);
-
-                if (res == null || !res.closed)
-                    return false;
-            }
-
-            return true;
-        }
-
-        /**
-         * Cancels the query.
-         */
-        void cancel(boolean forceQryCancel) {
-            if (canceled)
-                return;
-
-            canceled = true;
-
-            for (int i = 0; i < results.length(); i++) {
-                QueryResult res = results.get(i);
-
-                if (res != null) {
-                    res.close();
-
-                    continue;
-                }
-
-                if (forceQryCancel) {
-                    GridQueryCancel cancel = cancels[i];
-
-                    if (cancel != null)
-                        cancel.cancel();
-                }
-            }
-        }
-    }
-
-    /**
-     * Result for a single part of the query.
-     */
-    private class QueryResult implements AutoCloseable {
-        /** */
-        private final ResultInterface res;
-
-        /** */
-        private final ResultSet rs;
-
-        /** Kernal context. */
-        private final GridKernalContext ctx;
-
-        /** */
-        private final String cacheName;
-
-        /** */
-        private final GridCacheSqlQuery qry;
-
-        /** */
-        private final UUID qrySrcNodeId;
-
-        /** */
-        private final int cols;
-
-        /** */
-        private int page;
-
-        /** */
-        private final int rowCnt;
-
-        /** */
-        private boolean cpNeeded;
-
-        /** */
-        private volatile boolean closed;
-
-        /** */
-        private final Object[] params;
-
-        /**
-         * @param rs Result set.
-         * @param ctx Kernal context.
-         * @param cacheName Cache name.
-         * @param qrySrcNodeId Query source node.
-         * @param qry Query.
-         * @param params Query params.
-         */
-        private QueryResult(ResultSet rs, GridKernalContext ctx, @Nullable String cacheName,
-            UUID qrySrcNodeId, GridCacheSqlQuery qry, Object[] params) {
-            this.ctx = ctx;
-            this.cacheName = cacheName;
-            this.qry = qry;
-            this.params = params;
-            this.qrySrcNodeId = qrySrcNodeId;
-            this.cpNeeded = F.eq(ctx.localNodeId(), qrySrcNodeId);
-
-            if (rs != null) {
-                this.rs = rs;
-                try {
-                    res = (ResultInterface)RESULT_FIELD.get(rs);
-                }
-                catch (IllegalAccessException e) {
-                    throw new IllegalStateException(e); // Must not happen.
-                }
-
-                rowCnt = res.getRowCount();
-                cols = res.getVisibleColumnCount();
-            }
-            else {
-                this.rs = null;
-                this.res = null;
-                this.cols = -1;
-                this.rowCnt = -1;
-
-                closed = true;
-            }
-        }
-
-        /**
-         * @param rows Collection to fetch into.
-         * @param pageSize Page size.
-         * @return {@code true} If there are no more rows available.
-         */
-        synchronized boolean fetchNextPage(List<Value[]> rows, int pageSize) {
-            if (closed)
-                return true;
-
-            boolean readEvt = cacheName != null && ctx.event().isRecordable(EVT_CACHE_QUERY_OBJECT_READ);
-
-            page++;
-
-            for (int i = 0 ; i < pageSize; i++) {
-                if (!res.next())
-                    return true;
-
-                Value[] row = res.currentRow();
-
-                if (cpNeeded) {
-                    boolean copied = false;
-
-                    for (int j = 0; j < row.length; j++) {
-                        Value val = row[j];
-
-                        if (val instanceof GridH2ValueCacheObject) {
-                            GridH2ValueCacheObject valCacheObj = (GridH2ValueCacheObject)val;
-
-                            row[j] = new GridH2ValueCacheObject(valCacheObj.getCacheObject(), h2.objectContext()) {
-                                @Override public Object getObject() {
-                                    return getObject(true);
-                                }
-                            };
-
-                            copied = true;
-                        }
-                    }
-
-                    if (i == 0 && !copied)
-                        cpNeeded = false; // No copy on read caches, skip next checks.
-                }
-
-                assert row != null;
-
-                if (readEvt) {
-                    ctx.event().record(new CacheQueryReadEvent<>(
-                        ctx.discovery().localNode(),
-                        "SQL fields query result set row read.",
-                        EVT_CACHE_QUERY_OBJECT_READ,
-                        CacheQueryType.SQL.name(),
-                        cacheName,
-                        null,
-                        qry.query(),
-                        null,
-                        null,
-                        params,
-                        qrySrcNodeId,
-                        null,
-                        null,
-                        null,
-                        null,
-                        row(row)));
-                }
-
-                rows.add(res.currentRow());
-            }
-
-            return false;
-        }
-
-        /**
-         * @param row Values array row.
-         * @return Objects list row.
-         */
-        private List<?> row(Value[] row) {
-            List<Object> res = new ArrayList<>(row.length);
-
-            for (Value v : row)
-                res.add(v.getObject());
-
-            return res;
-        }
-
-        /** {@inheritDoc} */
-        @Override public synchronized void close() {
-            if (closed)
-                return;
-
-            closed = true;
-
-            U.close(rs, log);
-        }
-    }
-
-    /**
-     * Fake reservation object for replicated caches.
-     */
-    private static class ReplicatedReservation implements GridReservable {
-        /** */
-        static final ReplicatedReservation INSTANCE = new ReplicatedReservation();
-
-        /** {@inheritDoc} */
-        @Override public boolean reserve() {
-            throw new IllegalStateException();
-        }
-
-        /** {@inheritDoc} */
-        @Override public void release() {
-            throw new IllegalStateException();
-        }
-    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapNodeResults.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapNodeResults.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapNodeResults.java
new file mode 100644
index 0000000..d5ea357
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapNodeResults.java
@@ -0,0 +1,108 @@
+/*
+ * 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.query.h2.twostep;
+
+import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap;
+import org.jsr166.ConcurrentHashMap8;
+
+import java.util.concurrent.ConcurrentMap;
+
+import static org.jsr166.ConcurrentLinkedHashMap.QueuePolicy.PER_SEGMENT_Q;
+
+/**
+ * Mapper node results.
+ */
+class MapNodeResults {
+    /** */
+    private final ConcurrentMap<MapRequestKey, MapQueryResults> res = new ConcurrentHashMap8<>();
+
+    /** */
+    private final GridBoundedConcurrentLinkedHashMap<Long, Boolean> qryHist =
+        new GridBoundedConcurrentLinkedHashMap<>(1024, 1024, 0.75f, 64, PER_SEGMENT_Q);
+
+    /**
+     * @param reqId Query Request ID.
+     * @return {@code False} if query was already cancelled.
+     */
+    boolean cancelled(long reqId) {
+        return qryHist.get(reqId) != null;
+    }
+
+    /**
+     * @param reqId Query Request ID.
+     * @return {@code True} if cancelled.
+     */
+    boolean onCancel(long reqId) {
+        Boolean old = qryHist.putIfAbsent(reqId, Boolean.FALSE);
+
+        return old == null;
+    }
+
+    /**
+     * @param reqId Query Request ID.
+     * @param segmentId Index segment ID.
+     * @return query partial results.
+     */
+    public MapQueryResults get(long reqId, int segmentId) {
+        return res.get(new MapRequestKey(reqId, segmentId));
+    }
+
+    /**
+     * Cancel all thread of given request.
+     * @param reqId Request ID.
+     */
+    public void cancelRequest(long reqId) {
+        for (MapRequestKey key : res.keySet()) {
+            if (key.requestId() == reqId) {
+                MapQueryResults removed = res.remove(key);
+
+                if (removed != null)
+                    removed.cancel(true);
+            }
+        }
+    }
+
+    /**
+     * @param reqId Query Request ID.
+     * @param segmentId Index segment ID.
+     * @param qr Query Results.
+     * @return {@code True} if removed.
+     */
+    public boolean remove(long reqId, int segmentId, MapQueryResults qr) {
+        return res.remove(new MapRequestKey(reqId, segmentId), qr);
+    }
+
+    /**
+     * @param reqId Query Request ID.
+     * @param segmentId Index segment ID.
+     * @param qr Query Results.
+     * @return previous value.
+     */
+    public MapQueryResults put(long reqId, int segmentId, MapQueryResults qr) {
+        return res.put(new MapRequestKey(reqId, segmentId), qr);
+    }
+
+    /**
+     * Cancel all node queries.
+     */
+    public void cancelAll() {
+        for (MapQueryResults ress : res.values())
+            ress.cancel(true);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResult.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResult.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResult.java
new file mode 100644
index 0000000..4799e03
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResult.java
@@ -0,0 +1,258 @@
+/*
+ * 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.query.h2.twostep;
+
+import org.apache.ignite.events.CacheQueryReadEvent;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.cache.query.CacheQueryType;
+import org.apache.ignite.internal.processors.cache.query.GridCacheSqlQuery;
+import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+import org.apache.ignite.internal.processors.query.h2.opt.GridH2ValueCacheObject;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.h2.jdbc.JdbcResultSet;
+import org.h2.result.ResultInterface;
+import org.h2.value.Value;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.Field;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static org.apache.ignite.events.EventType.EVT_CACHE_QUERY_OBJECT_READ;
+
+/**
+ * Mapper result for a single part of the query.
+ */
+class MapQueryResult implements AutoCloseable {
+    /** */
+    private static final Field RESULT_FIELD;
+
+    /*
+     * Initialize.
+     */
+    static {
+        try {
+            RESULT_FIELD = JdbcResultSet.class.getDeclaredField("result");
+
+            RESULT_FIELD.setAccessible(true);
+        }
+        catch (NoSuchFieldException e) {
+            throw new IllegalStateException("Check H2 version in classpath.", e);
+        }
+    }
+
+    /** Indexing. */
+    private final IgniteH2Indexing h2;
+
+    /** */
+    private final ResultInterface res;
+
+    /** */
+    private final ResultSet rs;
+
+    /** */
+    private final String cacheName;
+
+    /** */
+    private final GridCacheSqlQuery qry;
+
+    /** */
+    private final UUID qrySrcNodeId;
+
+    /** */
+    private final int cols;
+
+    /** */
+    private int page;
+
+    /** */
+    private final int rowCnt;
+
+    /** */
+    private boolean cpNeeded;
+
+    /** */
+    private volatile boolean closed;
+
+    /** */
+    private final Object[] params;
+
+    /**
+     * @param rs Result set.
+     * @param cacheName Cache name.
+     * @param qrySrcNodeId Query source node.
+     * @param qry Query.
+     * @param params Query params.
+     */
+    MapQueryResult(IgniteH2Indexing h2, ResultSet rs, @Nullable String cacheName,
+        UUID qrySrcNodeId, GridCacheSqlQuery qry, Object[] params) {
+        this.h2 = h2;
+        this.cacheName = cacheName;
+        this.qry = qry;
+        this.params = params;
+        this.qrySrcNodeId = qrySrcNodeId;
+        this.cpNeeded = F.eq(h2.kernalContext().localNodeId(), qrySrcNodeId);
+
+        if (rs != null) {
+            this.rs = rs;
+            try {
+                res = (ResultInterface)RESULT_FIELD.get(rs);
+            }
+            catch (IllegalAccessException e) {
+                throw new IllegalStateException(e); // Must not happen.
+            }
+
+            rowCnt = res.getRowCount();
+            cols = res.getVisibleColumnCount();
+        }
+        else {
+            this.rs = null;
+            this.res = null;
+            this.cols = -1;
+            this.rowCnt = -1;
+
+            closed = true;
+        }
+    }
+
+    /**
+     * @return Page number.
+     */
+    int page() {
+        return page;
+    }
+
+    /**
+     * @return Row count.
+     */
+    int rowCount() {
+        return rowCnt;
+    }
+
+    /**
+     * @return Column ocunt.
+     */
+    int columnCount() {
+        return cols;
+    }
+
+    /**
+     * @return Closed flag.
+     */
+    boolean closed() {
+        return closed;
+    }
+
+    /**
+     * @param rows Collection to fetch into.
+     * @param pageSize Page size.
+     * @return {@code true} If there are no more rows available.
+     */
+    synchronized boolean fetchNextPage(List<Value[]> rows, int pageSize) {
+        if (closed)
+            return true;
+
+        boolean readEvt = cacheName != null && h2.kernalContext().event().isRecordable(EVT_CACHE_QUERY_OBJECT_READ);
+
+        page++;
+
+        for (int i = 0 ; i < pageSize; i++) {
+            if (!res.next())
+                return true;
+
+            Value[] row = res.currentRow();
+
+            if (cpNeeded) {
+                boolean copied = false;
+
+                for (int j = 0; j < row.length; j++) {
+                    Value val = row[j];
+
+                    if (val instanceof GridH2ValueCacheObject) {
+                        GridH2ValueCacheObject valCacheObj = (GridH2ValueCacheObject)val;
+
+                        row[j] = new GridH2ValueCacheObject(valCacheObj.getCacheObject(), h2.objectContext()) {
+                            @Override public Object getObject() {
+                                return getObject(true);
+                            }
+                        };
+
+                        copied = true;
+                    }
+                }
+
+                if (i == 0 && !copied)
+                    cpNeeded = false; // No copy on read caches, skip next checks.
+            }
+
+            assert row != null;
+
+            if (readEvt) {
+                GridKernalContext ctx = h2.kernalContext();
+
+                ctx.event().record(new CacheQueryReadEvent<>(
+                    ctx.discovery().localNode(),
+                    "SQL fields query result set row read.",
+                    EVT_CACHE_QUERY_OBJECT_READ,
+                    CacheQueryType.SQL.name(),
+                    cacheName,
+                    null,
+                    qry.query(),
+                    null,
+                    null,
+                    params,
+                    qrySrcNodeId,
+                    null,
+                    null,
+                    null,
+                    null,
+                    row(row)));
+            }
+
+            rows.add(res.currentRow());
+        }
+
+        return false;
+    }
+
+    /**
+     * @param row Values array row.
+     * @return Objects list row.
+     */
+    private List<?> row(Value[] row) {
+        List<Object> res = new ArrayList<>(row.length);
+
+        for (Value v : row)
+            res.add(v.getObject());
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public synchronized void close() {
+        if (closed)
+            return;
+
+        closed = true;
+
+        U.closeQuiet(rs);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResults.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResults.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResults.java
new file mode 100644
index 0000000..7ad1d14
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapQueryResults.java
@@ -0,0 +1,155 @@
+/*
+ * 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.query.h2.twostep;
+
+import org.apache.ignite.internal.processors.cache.query.GridCacheSqlQuery;
+import org.apache.ignite.internal.processors.query.GridQueryCancel;
+import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+import org.jetbrains.annotations.Nullable;
+
+import java.sql.ResultSet;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+/**
+ * Mapper query results.
+ */
+class MapQueryResults {
+    /** H@ indexing. */
+    private final IgniteH2Indexing h2;
+
+    /** */
+    private final long qryReqId;
+
+    /** */
+    private final AtomicReferenceArray<MapQueryResult> results;
+
+    /** */
+    private final GridQueryCancel[] cancels;
+
+    /** */
+    private final String cacheName;
+
+    /** */
+    private volatile boolean cancelled;
+
+    /**
+     * @param qryReqId Query request ID.
+     * @param qrys Number of queries.
+     * @param cacheName Cache name.
+     */
+    @SuppressWarnings("unchecked")
+    MapQueryResults(IgniteH2Indexing h2, long qryReqId, int qrys,
+        @Nullable String cacheName) {
+        this.h2 = h2;
+        this.qryReqId = qryReqId;
+        this.cacheName = cacheName;
+
+        results = new AtomicReferenceArray<>(qrys);
+        cancels = new GridQueryCancel[qrys];
+
+        for (int i = 0; i < cancels.length; i++)
+            cancels[i] = new GridQueryCancel();
+    }
+
+    /**
+     * @param qry Query result index.
+     * @return Query result.
+     */
+    MapQueryResult result(int qry) {
+        return results.get(qry);
+    }
+
+    /**
+     * Get cancel token for query.
+     *
+     * @param qryIdx Query index.
+     * @return Cancel token.
+     */
+    GridQueryCancel queryCancel(int qryIdx) {
+        return cancels[qryIdx];
+    }
+
+    /**
+     * @param qry Query result index.
+     * @param q Query object.
+     * @param qrySrcNodeId Query source node.
+     * @param rs Result set.
+     */
+    void addResult(int qry, GridCacheSqlQuery q, UUID qrySrcNodeId, ResultSet rs, Object[] params) {
+        MapQueryResult res = new MapQueryResult(h2, rs, cacheName, qrySrcNodeId, q, params);
+
+        if (!results.compareAndSet(qry, null, res))
+            throw new IllegalStateException();
+    }
+
+    /**
+     * @return {@code true} If all results are closed.
+     */
+    boolean isAllClosed() {
+        for (int i = 0; i < results.length(); i++) {
+            MapQueryResult res = results.get(i);
+
+            if (res == null || !res.closed())
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Cancels the query.
+     */
+    void cancel(boolean forceQryCancel) {
+        if (cancelled)
+            return;
+
+        cancelled = true;
+
+        for (int i = 0; i < results.length(); i++) {
+            MapQueryResult res = results.get(i);
+
+            if (res != null) {
+                res.close();
+
+                continue;
+            }
+
+            if (forceQryCancel) {
+                GridQueryCancel cancel = cancels[i];
+
+                if (cancel != null)
+                    cancel.cancel();
+            }
+        }
+    }
+
+    /**
+     * @return Cancel flag.
+     */
+    boolean cancelled() {
+        return cancelled;
+    }
+
+    /**
+     * @return Query request ID.
+     */
+    long queryRequestId() {
+        return qryReqId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReplicatedReservation.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReplicatedReservation.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReplicatedReservation.java
new file mode 100644
index 0000000..dd8237b
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReplicatedReservation.java
@@ -0,0 +1,38 @@
+/*
+ * 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.query.h2.twostep;
+
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridReservable;
+
+/**
+ * Mapper fake reservation object for replicated caches.
+ */
+class MapReplicatedReservation implements GridReservable {
+    /** */
+    static final MapReplicatedReservation INSTANCE = new MapReplicatedReservation();
+
+    /** {@inheritDoc} */
+    @Override public boolean reserve() {
+        throw new IllegalStateException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void release() {
+        throw new IllegalStateException();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapRequestKey.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapRequestKey.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapRequestKey.java
new file mode 100644
index 0000000..6feb8ea
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapRequestKey.java
@@ -0,0 +1,65 @@
+/*
+ * 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.query.h2.twostep;
+
+/**
+ * Mapper request key.
+ */
+class MapRequestKey {
+    /** */
+    private long reqId;
+
+    /** */
+    private int segmentId;
+
+    /** Constructor */
+    MapRequestKey(long reqId, int segmentId) {
+        this.reqId = reqId;
+        this.segmentId = segmentId;
+    }
+
+    /**
+     * @return Request ID.
+     */
+    public long requestId() {
+        return reqId;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        MapRequestKey other = (MapRequestKey)o;
+
+        return reqId == other.reqId && segmentId == other.segmentId;
+
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = (int)(reqId ^ (reqId >>> 32));
+
+        res = 31 * res + segmentId;
+
+        return res;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/879f1910/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReservationKey.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReservationKey.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReservationKey.java
new file mode 100644
index 0000000..9d2d7ba
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/MapReservationKey.java
@@ -0,0 +1,73 @@
+/*
+ * 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.query.h2.twostep;
+
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.util.typedef.F;
+
+/**
+ * Mapper reservation key.
+ */
+public class MapReservationKey {
+    /** Cache name. */
+    private final String cacheName;
+
+    /** Topology version. */
+    private final AffinityTopologyVersion topVer;
+
+    /**
+     * Constructor.
+     *
+     * @param cacheName Cache name.
+     * @param topVer Topology version.
+     */
+    public MapReservationKey(String cacheName, AffinityTopologyVersion topVer) {
+        this.cacheName = cacheName;
+        this.topVer = topVer;
+    }
+
+    /**
+     * @return Cache name.
+     */
+    public String cacheName() {
+        return cacheName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        MapReservationKey other = (MapReservationKey)o;
+
+        return F.eq(cacheName, other.cacheName) && F.eq(topVer, other.topVer);
+
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        int res = cacheName != null ? cacheName.hashCode() : 0;
+
+        res = 31 * res + (topVer != null ? topVer.hashCode() : 0);
+
+        return res;
+    }
+}


[17/29] ignite git commit: IGNITE-6012 Refactored GridJettyRestHandler.processRequest(): replace mapper.writeValueAsString with writeValue(stream, v). (cherry picked from commit 3a390c8)

Posted by nt...@apache.org.
IGNITE-6012 Refactored GridJettyRestHandler.processRequest(): replace mapper.writeValueAsString with writeValue(stream, v).
(cherry picked from commit 3a390c8)


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

Branch: refs/heads/ignite-5947
Commit: 8b2461942c18f228c0107020aa28c03711bdceda
Parents: 5c20978
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Fri Aug 11 11:07:26 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Fri Aug 11 11:22:27 2017 +0700

----------------------------------------------------------------------
 .../http/jetty/GridJettyRestHandler.java        | 31 +++++++-------------
 1 file changed, 10 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/8b246194/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
----------------------------------------------------------------------
diff --git a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
index c864a10..327c13a 100644
--- a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
+++ b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
@@ -34,6 +34,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -356,41 +357,29 @@ public class GridJettyRestHandler extends AbstractHandler {
 
             U.error(log, "Failed to process HTTP request [action=" + act + ", req=" + req + ']', e);
 
-            cmdRes = new GridRestResponse(STATUS_FAILED, e.getMessage());
-
             if (e instanceof Error)
                 throw (Error)e;
-        }
-
-        String json;
 
-        try {
-            json = jsonMapper.writeValueAsString(cmdRes);
+            cmdRes = new GridRestResponse(STATUS_FAILED, e.getMessage());
         }
-        catch (JsonProcessingException e1) {
-            U.error(log, "Failed to convert response to JSON: " + cmdRes, e1);
 
-            GridRestResponse resFailed = new GridRestResponse(STATUS_FAILED, e1.getMessage());
+        try {
+            ServletOutputStream os = res.getOutputStream();
 
             try {
-                json = jsonMapper.writeValueAsString(resFailed);
+                jsonMapper.writeValue(os, cmdRes);
             }
-            catch (JsonProcessingException e2) {
-                json = "{\"successStatus\": \"1\", \"error:\" \"" + e2.getMessage() + "\"}}";
-            }
-        }
-
-        try {
-            if (log.isDebugEnabled())
-                log.debug("Parsed command response into JSON object: " + json);
+            catch (JsonProcessingException e) {
+                U.error(log, "Failed to convert response to JSON: " + cmdRes, e);
 
-            res.getWriter().write(json);
+                jsonMapper.writeValue(os, F.asMap("successStatus", STATUS_FAILED, "error", e.getMessage()));
+            }
 
             if (log.isDebugEnabled())
                 log.debug("Processed HTTP request [action=" + act + ", jsonRes=" + cmdRes + ", req=" + req + ']');
         }
         catch (IOException e) {
-            U.error(log, "Failed to send HTTP response: " + json, e);
+            U.error(log, "Failed to send HTTP response: " + cmdRes, e);
         }
     }
 


[04/29] ignite git commit: Merge branch ignite-2.1.3 into ignite-2.1.4

Posted by nt...@apache.org.
Merge branch ignite-2.1.3 into ignite-2.1.4


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

Branch: refs/heads/ignite-5947
Commit: 772d462b68c7de8517d1f61e2e05ec8eefb18eac
Parents: e255a56 6bdad4d
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Thu Aug 3 11:55:15 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Thu Aug 3 11:55:15 2017 +0700

----------------------------------------------------------------------
 .../apache/ignite/IgniteSystemProperties.java   |   6 +
 .../IgniteDiagnosticPrepareContext.java         |   3 +-
 .../apache/ignite/internal/IgniteKernal.java    |   3 +-
 .../mem/file/MappedFileMemoryProvider.java      |   3 +-
 .../GridCachePartitionExchangeManager.java      |   2 +-
 .../processors/cache/GridCacheProcessor.java    |  16 +-
 .../processors/cache/GridCacheUtils.java        |   7 +-
 .../cache/IgniteCacheOffheapManagerImpl.java    |  26 ++-
 .../processors/cache/IgniteCacheProxyImpl.java  |  24 ++-
 .../GridDhtPartitionsExchangeFuture.java        |  20 +-
 .../GridCacheDatabaseSharedManager.java         |   7 +-
 .../persistence/freelist/FreeListImpl.java      |  18 +-
 .../wal/FileWriteAheadLogManager.java           |  37 +++-
 .../reader/StandaloneWalRecordsIterator.java    |   4 +-
 .../cluster/GridClusterStateProcessor.java      |   3 +-
 .../datastructures/GridCacheLockImpl.java       |  13 +-
 .../processors/odbc/SqlListenerProcessor.java   |   3 +-
 .../ignite/internal/util/nio/GridNioServer.java |   7 +-
 .../internal/visor/debug/VisorThreadInfo.java   |  10 +-
 .../internal/visor/query/VisorQueryTask.java    |   2 +-
 .../visor/query/VisorScanQueryTask.java         |   2 +-
 .../ignite/spi/discovery/tcp/ServerImpl.java    |  38 ++--
 .../cache/store/jdbc/model/BinaryTest.java      |   1 -
 .../processors/cache/IgniteCacheGroupsTest.java |  22 +-
 .../IgnitePdsCacheRebalancingAbstractTest.java  |   2 +
 .../TxOptimisticDeadlockDetectionTest.java      |   2 +
 .../ignite/tests/p2p/JobStealingTask.java       |  12 +-
 .../org/apache/ignite/tests/p2p/NodeFilter.java |  30 +++
 .../hadoop/jobtracker/HadoopJobTracker.java     |  24 ++-
 .../hadoop/shuffle/HadoopShuffleJob.java        |   5 +-
 .../processors/query/h2/IgniteH2Indexing.java   |  21 +-
 .../cache/index/H2DynamicTableSelfTest.java     |  32 +++
 .../apache/ignite/stream/mqtt/MqttStreamer.java |   6 +-
 .../include/ignite/binary/binary_writer.h       |   4 +-
 .../ignite/impl/binary/binary_reader_impl.h     |  50 +++--
 .../ignite/impl/binary/binary_type_impl.h       |  67 ++++++
 .../ignite/impl/binary/binary_writer_impl.h     |  43 ++--
 .../src/impl/binary/binary_reader_impl.cpp      |  63 +++---
 .../src/impl/binary/binary_writer_impl.cpp      |  41 ++--
 .../core-test/config/cache-query-default.xml    |  29 +++
 .../src/binary_reader_writer_raw_test.cpp       |  36 ++++
 .../core-test/src/binary_reader_writer_test.cpp | 135 +++++++++---
 .../cpp/core-test/src/cache_query_test.cpp      | 215 ++++++++++++++++++-
 .../cpp/core-test/src/cluster_test.cpp          |  13 ++
 .../ignite/cache/query/query_fields_row.h       |  28 +++
 .../ignite/cache/query/query_sql_fields.h       |  13 +-
 .../platforms/cpp/core/include/ignite/ignite.h  |  15 ++
 .../ignite/impl/cache/query/query_argument.h    |  63 ++++++
 .../impl/cache/query/query_fields_row_impl.h    |  29 +++
 .../ignite/impl/cluster/cluster_group_impl.h    |  15 ++
 .../cpp/core/include/ignite/impl/ignite_impl.h  |  24 ++-
 modules/platforms/cpp/core/src/ignite.cpp       |  10 +
 .../src/impl/cluster/cluster_group_impl.cpp     |  26 ++-
 .../platforms/cpp/core/src/impl/ignite_impl.cpp |   4 +
 .../spi/deployment/uri/UriDeploymentSpi.java    |   3 +-
 modules/web-console/backend/app/mongo.js        |   2 +-
 modules/web-console/backend/app/settings.js     |   3 +-
 modules/web-console/backend/index.js            |  16 +-
 modules/web-console/backend/middlewares/api.js  |  39 ++--
 .../web-console/backend/services/activities.js  |  12 +-
 modules/web-console/frontend/app/app.js         |  10 +-
 .../components/grid-item-selected/component.js  |  28 +++
 .../components/grid-item-selected/controller.js |  38 ++++
 .../app/components/grid-item-selected/index.js  |  24 +++
 .../components/grid-item-selected/template.pug  |  17 ++
 .../list-of-registered-users.tpl.pug            |   4 +-
 .../app/components/ui-grid-hovering/cell.js     |  48 +++++
 .../app/components/ui-grid-hovering/hovering.js |  31 +++
 .../app/components/ui-grid-hovering/index.js    |  30 +++
 .../app/components/ui-grid-hovering/style.scss  |  22 ++
 .../app/components/ui-grid-hovering/viewport.js |  42 ++++
 .../frontend/app/controllers/auth.controller.js |   9 +-
 .../app/modules/agent/AgentManager.service.js   |  24 +--
 .../app/modules/agent/AgentModal.service.js     |   8 +-
 .../configuration/generator/Maven.service.js    |  13 +-
 .../frontend/app/modules/demo/Demo.module.js    |  22 +-
 .../frontend/app/modules/sql/sql.controller.js  |  11 +-
 .../states/configuration/clusters/hadoop.pug    |   2 +-
 .../configuration/summary/summary.worker.js     |   4 +-
 .../frontend/app/modules/states/errors.state.js |   2 +-
 .../app/modules/states/password.state.js        |   2 +
 .../app/modules/states/profile.state.js         |   2 +-
 .../frontend/app/modules/states/signin.state.js |   6 +-
 .../app/modules/user/AclRoute.provider.js       |  50 -----
 .../frontend/app/modules/user/user.module.js    |  35 ++-
 .../frontend/app/services/Messages.service.js   |   7 +
 .../web-console/frontend/views/signin.tpl.pug   |   2 +-
 .../views/templates/agent-download.tpl.pug      |   2 -
 88 files changed, 1480 insertions(+), 424 deletions(-)
----------------------------------------------------------------------



[09/29] ignite git commit: Merge branch ignite-2.1.3 into ignite-2.1.4.

Posted by nt...@apache.org.
Merge branch ignite-2.1.3 into ignite-2.1.4.


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

Branch: refs/heads/ignite-5947
Commit: 4f02504475fd1e5cc3b9f4754856e44d20fdc1cb
Parents: 4e0385f 0eedf46
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Mon Aug 7 09:41:22 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Mon Aug 7 09:41:22 2017 +0700

----------------------------------------------------------------------
 .../binary/datagrid/CacheClientBinaryQueryExample.java       | 3 +++
 .../hide-on-state-change/hide-on-state-change.directive.js   | 8 ++------
 modules/web-console/frontend/views/index.pug                 | 8 ++++++++
 3 files changed, 13 insertions(+), 6 deletions(-)
----------------------------------------------------------------------



[13/29] ignite git commit: IGNITE-5452: GridTimeoutProcessor can hang on stop. This closes #2279.

Posted by nt...@apache.org.
IGNITE-5452: GridTimeoutProcessor can hang on stop. This closes #2279.


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

Branch: refs/heads/ignite-5947
Commit: ab18fdfcc4f6db1e54fb1f3b68ba7fbc31a7f6e7
Parents: 7c77b86
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Fri Jul 14 20:14:47 2017 +0300
Committer: Denis Mekhanikov <dm...@gmail.com>
Committed: Wed Aug 9 13:38:58 2017 +0300

----------------------------------------------------------------------
 .../timeout/GridTimeoutProcessor.java           |  18 +-
 .../IgniteTxRemoveTimeoutObjectsTest.java       | 194 +++++++++++++++++++
 .../timeout/GridTimeoutProcessorSelfTest.java   |  68 +++++--
 .../testsuites/IgniteCacheTestSuite3.java       |   4 +-
 4 files changed, 265 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/ab18fdfc/modules/core/src/main/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessor.java
index 9deca9a..8c71f76 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessor.java
@@ -37,7 +37,7 @@ import org.apache.ignite.thread.IgniteThread;
  */
 public class GridTimeoutProcessor extends GridProcessorAdapter {
     /** */
-    private final IgniteThread timeoutWorker;
+    private final TimeoutWorker timeoutWorker;
 
     /** Time-based sorted set for timeout objects. */
     private final GridConcurrentSkipListSet<GridTimeoutObject> timeoutObjs =
@@ -62,13 +62,12 @@ public class GridTimeoutProcessor extends GridProcessorAdapter {
     public GridTimeoutProcessor(GridKernalContext ctx) {
         super(ctx);
 
-        timeoutWorker = new IgniteThread(ctx.config().getIgniteInstanceName(), "grid-timeout-worker",
-            new TimeoutWorker());
+        timeoutWorker = new TimeoutWorker();
     }
 
     /** {@inheritDoc} */
     @Override public void start() {
-        timeoutWorker.start();
+        new IgniteThread(timeoutWorker).start();
 
         if (log.isDebugEnabled())
             log.debug("Timeout processor started.");
@@ -76,7 +75,7 @@ public class GridTimeoutProcessor extends GridProcessorAdapter {
 
     /** {@inheritDoc} */
     @Override public void stop(boolean cancel) throws IgniteCheckedException {
-        U.interrupt(timeoutWorker);
+        timeoutWorker.cancel();
         U.join(timeoutWorker);
 
         if (log.isDebugEnabled())
@@ -159,6 +158,13 @@ public class GridTimeoutProcessor extends GridProcessorAdapter {
                             timeoutObj.onTimeout();
                         }
                         catch (Throwable e) {
+                            if (isCancelled() && !(e instanceof Error)){
+                                if (log.isDebugEnabled())
+                                    log.debug("Error when executing timeout callback: " + timeoutObj);
+
+                                return;
+                            }
+
                             U.error(log, "Error when executing timeout callback: " + timeoutObj, e);
 
                             if (e instanceof Error)
@@ -170,7 +176,7 @@ public class GridTimeoutProcessor extends GridProcessorAdapter {
                 }
 
                 synchronized (mux) {
-                    while (true) {
+                    while (!isCancelled()) {
                         // Access of the first element must be inside of
                         // synchronization block, so we don't miss out
                         // on thread notification events sent from

http://git-wip-us.apache.org/repos/asf/ignite/blob/ab18fdfc/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
new file mode 100644
index 0000000..c0f9940
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
+import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
+import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionTimeoutException;
+
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
+
+/**
+ * Test correctness of rollback a transaction with timeout during the grid stop.
+ */
+public class IgniteTxRemoveTimeoutObjectsTest extends GridCacheAbstractSelfTest {
+    /** */
+    private static final int PUT_CNT = 1000;
+
+    /** {@inheritDoc} */
+    @Override protected int gridCount() {
+        return 3;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected long getTestTimeout() {
+        return 60_000;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testTxRemoveTimeoutObjects() throws Exception {
+        IgniteCache<Integer, Integer> cache0 = grid(0).cache(DEFAULT_CACHE_NAME);
+        IgniteCache<Integer, Integer> cache1 = grid(1).cache(DEFAULT_CACHE_NAME);
+
+        // start additional grid to be closed.
+        IgniteCache<Integer, Integer> cacheAdditional = startGrid(gridCount()).cache(DEFAULT_CACHE_NAME);
+
+        for (int i = 0; i < PUT_CNT; i++)
+            cache0.put(i, Integer.MAX_VALUE);
+
+        logTimeoutObjectsFrequency();
+
+        info("Tx1 started");
+        try (Transaction tx = grid(gridCount()).transactions().txStart(PESSIMISTIC, SERIALIZABLE, 100, PUT_CNT)) {
+            try {
+                for (int i = 0; i < PUT_CNT; i++) {
+                    cacheAdditional.put(i, Integer.MIN_VALUE);
+
+                    if (i % 100 == 0)
+                        logTimeoutObjectsFrequency();
+                }
+
+                U.sleep(200);
+
+                tx.commit();
+
+                fail("A timeout should have happened.");
+            }
+            catch (Exception e) {
+                assertTrue(X.hasCause(e, TransactionTimeoutException.class));
+            }
+        }
+
+        assertDoesNotContainLockTimeoutObjects();
+
+        logTimeoutObjectsFrequency();
+
+        stopGrid(gridCount());
+
+        awaitPartitionMapExchange();
+
+        info("Grid2 closed.");
+
+        assertDoesNotContainLockTimeoutObjects();
+
+        logTimeoutObjectsFrequency();
+
+        // Check that the values have not changed and lock can be acquired.
+        try (Transaction tx2 = grid(1).transactions().txStart(PESSIMISTIC, SERIALIZABLE)) {
+            info("Tx2 started");
+
+            for (int i = 0; i < PUT_CNT; i++) {
+                assertEquals(cache1.get(i).intValue(), Integer.MAX_VALUE);
+                cache1.put(i, i);
+
+                if (i % (PUT_CNT / 5) == 0)
+                    logTimeoutObjectsFrequency();
+            }
+
+            tx2.commit();
+        }
+
+        info("Tx2 stopped");
+
+        // Check that that changes committed.
+        for (int i = 0; i < PUT_CNT; i++)
+            assertEquals(cache0.get(i).intValue(), i);
+    }
+
+    /**
+     * Fails if at least one grid contains LockTimeoutObjects.
+     */
+    private void assertDoesNotContainLockTimeoutObjects() {
+        for (Ignite ignite : G.allGrids()) {
+            for (GridTimeoutObject object : getTimeoutObjects((IgniteEx)ignite)) {
+                if (object.getClass().getSimpleName().equals("LockTimeoutObject"))
+                    fail("Grids contain LockTimeoutObjects.");
+            }
+        }
+    }
+
+    /**
+     * Print the number of each timeout object type on each grid to the log.
+     */
+    private void logTimeoutObjectsFrequency() {
+        StringBuilder sb = new StringBuilder("Timeout objects frequency [");
+
+        for (Ignite ignite : G.allGrids()) {
+            IgniteEx igniteEx = (IgniteEx)ignite;
+
+            Map<String, Integer> objFreqMap = new HashMap<>();
+
+            Set<GridTimeoutObject> objs = getTimeoutObjects(igniteEx);
+
+            for (GridTimeoutObject obj : objs) {
+                String clsName = obj.getClass().getSimpleName();
+
+                Integer cnt = objFreqMap.get(clsName);
+
+                if (cnt == null)
+                    objFreqMap.put(clsName, 1);
+                else
+                    objFreqMap.put(clsName, cnt + 1);
+            }
+
+            sb.append("[")
+                .append(igniteEx.name()).append(": size=")
+                .append(objs.size()).append(", ");
+
+            for (Map.Entry<String, Integer> entry : objFreqMap.entrySet()) {
+                sb.append(entry.getKey()).append("=")
+                    .append(entry.getValue())
+                    .append(", ");
+            }
+
+            sb.delete(sb.length() - 2, sb.length())
+                .append("]; ");
+        }
+
+        sb.delete(sb.length() - 2, sb.length())
+            .append("]");
+
+        info(sb.toString()
+            .replaceAll("distributed.IgniteTxRollbackOnStopTest", "Grid"));
+    }
+
+    /**
+     * @param igniteEx IgniteEx.
+     * @return Set of timeout objects that process on current IgniteEx.
+     */
+    private Set<GridTimeoutObject> getTimeoutObjects(IgniteEx igniteEx) {
+        GridTimeoutProcessor timeout = igniteEx.context().timeout();
+
+        return GridTestUtils.getFieldValue(timeout, timeout.getClass(), "timeoutObjs");
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ab18fdfc/modules/core/src/test/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessorSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessorSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessorSelfTest.java
index eb248cf..606b102 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessorSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/timeout/GridTimeoutProcessorSelfTest.java
@@ -41,6 +41,11 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
     private GridTestKernalContext ctx;
 
     /** {@inheritDoc} */
+    @Override protected long getTestTimeout() {
+        return 60_000;
+    }
+
+    /** {@inheritDoc} */
     @Override protected void beforeTest() throws Exception {
         ctx = newContext();
 
@@ -84,7 +89,9 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
                 }
 
                 /** {@inheritDoc} */
-                @Override public long endTime() { return endTime; }
+                @Override public long endTime() {
+                    return endTime;
+                }
 
                 /** {@inheritDoc} */
                 @Override public void onTimeout() {
@@ -152,10 +159,14 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
                         private final long endTime = System.currentTimeMillis() + RAND.nextInt(1000) + 500;
 
                         /** {@inheritDoc} */
-                        @Override public IgniteUuid timeoutId() { return id; }
+                        @Override public IgniteUuid timeoutId() {
+                            return id;
+                        }
 
                         /** {@inheritDoc} */
-                        @Override public long endTime() { return endTime; }
+                        @Override public long endTime() {
+                            return endTime;
+                        }
 
                         /** {@inheritDoc} */
                         @Override public void onTimeout() {
@@ -307,9 +318,8 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
         assert timeObjs.size() == max;
 
         // Remove timeout objects so that they aren't able to times out (supposing the cycle takes less than 500 ms).
-        for (GridTimeoutObject obj : timeObjs) {
+        for (GridTimeoutObject obj : timeObjs)
             ctx.timeout().removeTimeoutObject(obj);
-        }
 
         Thread.sleep(1000);
 
@@ -350,7 +360,9 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
                         }
 
                         /** {@inheritDoc} */
-                        @Override public long endTime() { return endTime; }
+                        @Override public long endTime() {
+                            return endTime;
+                        }
 
                         /** {@inheritDoc} */
                         @Override public void onTimeout() {
@@ -370,9 +382,8 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
 
                 // Remove timeout objects so that they aren't able to times out
                 // (supposing the cycle takes less than 500 ms).
-                for (GridTimeoutObject obj : timeObjs) {
+                for (GridTimeoutObject obj : timeObjs)
                     ctx.timeout().removeTimeoutObject(obj);
-                }
             }
         }, threads, "timeout-test-worker");
 
@@ -381,6 +392,9 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
         assert callCnt.get() == 0;
     }
 
+    /**
+     * @throws Exception If test failed.
+     */
     public void testAddRemoveInterleaving() throws Exception {
         final AtomicInteger callCnt = new AtomicInteger(0);
 
@@ -430,9 +444,8 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
 
                 // Remove timeout objects so that they aren't able to times out
                 // (supposing the cycle takes less than 500 ms).
-                for (GridTimeoutObject obj : timeObjs) {
+                for (GridTimeoutObject obj : timeObjs)
                     ctx.timeout().removeTimeoutObject(obj);
-                }
             }
         }, 100, "timeout-test-worker");
 
@@ -516,10 +529,14 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
             private int cnt;
 
             /** {@inheritDoc} */
-            @Override public IgniteUuid timeoutId() { return id; }
+            @Override public IgniteUuid timeoutId() {
+                return id;
+            }
 
             /** {@inheritDoc} */
-            @Override public long endTime() { return endTime; }
+            @Override public long endTime() {
+                return endTime;
+            }
 
             /** {@inheritDoc} */
             @Override public void onTimeout() {
@@ -608,4 +625,31 @@ public class GridTimeoutProcessorSelfTest extends GridCommonAbstractTest {
 
         assert latch.await(3000, MILLISECONDS);
     }
+
+    /**
+     * Test that eaten {@link InterruptedException} will not hang on the closing of the grid.
+     *
+     * @throws Exception If test failed.
+     */
+    public void testCancelingWithClearedInterruptedFlag() throws Exception {
+        final CountDownLatch onTimeoutCalled = new CountDownLatch(1);
+
+        ctx.timeout().addTimeoutObject(new GridTimeoutObjectAdapter(10) {
+            /** {@inheritDoc} */
+            @Override public void onTimeout() {
+                try {
+                    onTimeoutCalled.countDown();
+
+                    // Wait for CacheProcessor has stopped and cause InterruptedException
+                    // which clears interrupted flag.
+                    Thread.sleep(Long.MAX_VALUE);
+                }
+                catch (InterruptedException ignore) {
+                    // No-op.
+                }
+            }
+        });
+
+        onTimeoutCalled.await();
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/ab18fdfc/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
index 58e9dc3..a6be07e 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
@@ -36,9 +36,9 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheGroupsTest;
 import org.apache.ignite.internal.processors.cache.IgniteCacheInterceptorSelfTestSuite;
 import org.apache.ignite.internal.processors.cache.IgniteCacheScanPredicateDeploymentSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheAsyncOperationsTest;
-import org.apache.ignite.internal.processors.cache.distributed.CacheGroupsPreloadTest;
 import org.apache.ignite.internal.processors.cache.distributed.GridCacheMixedModeSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.IgniteTxGetAfterStopTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteTxRemoveTimeoutObjectsTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDaemonNodePartitionedSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCachePartitionedOnlyP2PDisabledByteArrayValuesSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.dht.GridCachePartitionedOnlyP2PEnabledByteArrayValuesSelfTest;
@@ -199,6 +199,8 @@ public class IgniteCacheTestSuite3 extends TestSuite {
 
         suite.addTestSuite(CacheAsyncOperationsTest.class);
 
+        suite.addTestSuite(IgniteTxRemoveTimeoutObjectsTest.class);
+
         return suite;
     }
 }


[23/29] ignite git commit: GG-12629 Backport IGNITE-5961 to 8.1.4

Posted by nt...@apache.org.
GG-12629 Backport IGNITE-5961 to 8.1.4


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

Branch: refs/heads/ignite-5947
Commit: 2f38065cd10fd61d51771d14188380dc7cc74ed7
Parents: c23a2dc
Author: Ivan Rakov <iv...@gmail.com>
Authored: Mon Aug 14 16:44:50 2017 +0300
Committer: Ivan Rakov <iv...@gmail.com>
Committed: Mon Aug 14 16:45:26 2017 +0300

----------------------------------------------------------------------
 .../internal/pagemem/store/PageStore.java       |   5 +
 .../cache/persistence/file/FilePageStore.java   |  56 +++++----
 .../persistence/file/FilePageStoreFactory.java  |  35 ++++++
 .../persistence/file/FilePageStoreManager.java  |  17 +--
 .../cache/persistence/file/FilePageStoreV2.java |  53 +++++++++
 .../file/FileVersionCheckingFactory.java        | 116 +++++++++++++++++++
 ...gnitePdsRecoveryAfterFileCorruptionTest.java |   2 +-
 7 files changed, 252 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
index 4698a6b..f6e577c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/store/PageStore.java
@@ -95,4 +95,9 @@ public interface PageStore {
      * @throws IgniteCheckedException If sync failed (IO error occurred).
      */
     public void ensure() throws IgniteCheckedException;
+
+    /**
+     * @return Page store version.
+     */
+    public int version();
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
index a7ca13c..e6c5379 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStore.java
@@ -45,10 +45,10 @@ public class FilePageStore implements PageStore {
     private static final long SIGNATURE = 0xF19AC4FE60C530B8L;
 
     /** File version. */
-    private static final int VERSION = 1;
+    public static final int VERSION = 1;
 
     /** Allocated field offset. */
-    public static final int HEADER_SIZE = 8/*SIGNATURE*/ + 4/*VERSION*/ + 1/*type*/ + 4/*page size*/;
+    static final int HEADER_SIZE = 8/*SIGNATURE*/ + 4/*VERSION*/ + 1/*type*/ + 4/*page size*/;
 
     /** */
     private final File cfgFile;
@@ -57,7 +57,7 @@ public class FilePageStore implements PageStore {
     private final byte type;
 
     /** Database configuration. */
-    private final MemoryConfiguration dbCfg;
+    protected final MemoryConfiguration dbCfg;
 
     /** Factory to provide I/O interfaces for read/write operations with files */
     private final FileIOFactory ioFactory;
@@ -103,20 +103,36 @@ public class FilePageStore implements PageStore {
 
     /** {@inheritDoc} */
     @Override public boolean exists() {
-        return cfgFile.exists() && cfgFile.length() > HEADER_SIZE;
+        return cfgFile.exists() && cfgFile.length() > headerSize();
     }
 
     /**
+     * Size of page store header.
+     */
+    public int headerSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * Page store version.
+     */
+    public int version() {
+        return VERSION;
+    }
+
+    /**
+     * Creates header for current version file store. Doesn't init the store.
+     *
      * @param type Type.
      * @param pageSize Page size.
      * @return Byte buffer instance.
      */
-    public static ByteBuffer header(byte type, int pageSize) {
-        ByteBuffer hdr = ByteBuffer.allocate(HEADER_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+    public ByteBuffer header(byte type, int pageSize) {
+        ByteBuffer hdr = ByteBuffer.allocate(headerSize()).order(ByteOrder.LITTLE_ENDIAN);
 
         hdr.putLong(SIGNATURE);
 
-        hdr.putInt(VERSION);
+        hdr.putInt(version());
 
         hdr.put(type);
 
@@ -142,7 +158,7 @@ public class FilePageStore implements PageStore {
         }
 
         //there is 'super' page in every file
-        return HEADER_SIZE + dbCfg.getPageSize();
+        return headerSize() + dbCfg.getPageSize();
     }
 
     /**
@@ -150,7 +166,7 @@ public class FilePageStore implements PageStore {
      */
     private long checkFile() throws IgniteCheckedException {
         try {
-            ByteBuffer hdr = ByteBuffer.allocate(HEADER_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+            ByteBuffer hdr = ByteBuffer.allocate(headerSize()).order(ByteOrder.LITTLE_ENDIAN);
 
             while (hdr.remaining() > 0)
                 fileIO.read(hdr);
@@ -166,9 +182,9 @@ public class FilePageStore implements PageStore {
 
             int ver = hdr.getInt();
 
-            if (VERSION != ver)
+            if (version() != ver)
                 throw new IgniteCheckedException("Failed to verify store file (invalid file version)" +
-                    " [expectedVersion=" + VERSION +
+                    " [expectedVersion=" + version() +
                     ", fileVersion=" + ver + "]");
 
             byte type = hdr.get();
@@ -187,10 +203,10 @@ public class FilePageStore implements PageStore {
 
             long fileSize = cfgFile.length();
 
-            if (fileSize == HEADER_SIZE) // Every file has a special meta page.
-                fileSize = pageSize + HEADER_SIZE;
+            if (fileSize == headerSize()) // Every file has a special meta page.
+                fileSize = pageSize + headerSize();
 
-            if ((fileSize - HEADER_SIZE) % pageSize != 0)
+            if ((fileSize - headerSize()) % pageSize != 0)
                 throw new IgniteCheckedException("Failed to verify store file (invalid file size)" +
                     " [fileSize=" + U.hexLong(fileSize) +
                     ", pageSize=" + U.hexLong(pageSize) + ']');
@@ -346,9 +362,9 @@ public class FilePageStore implements PageStore {
         init();
 
         try {
-            assert buf.remaining() == HEADER_SIZE;
+            assert buf.remaining() == headerSize();
 
-            int len = HEADER_SIZE;
+            int len = headerSize();
 
             long off = 0;
 
@@ -425,7 +441,7 @@ public class FilePageStore implements PageStore {
 
             long off = pageOffset(pageId);
 
-            assert (off >= 0 && off + pageSize <= allocated.get() + HEADER_SIZE) || recover :
+            assert (off >= 0 && off + pageSize <= allocated.get() + headerSize()) || recover :
                 "off=" + U.hexLong(off) + ", allocated=" + U.hexLong(allocated.get()) + ", pageId=" + U.hexLong(pageId);
 
             assert pageBuf.capacity() == pageSize;
@@ -463,7 +479,7 @@ public class FilePageStore implements PageStore {
 
     /** {@inheritDoc} */
     @Override public long pageOffset(long pageId) {
-        return (long) PageIdUtils.pageIndex(pageId) * pageSize + HEADER_SIZE;
+        return (long) PageIdUtils.pageIndex(pageId) * pageSize + headerSize();
     }
 
     /** {@inheritDoc} */
@@ -494,7 +510,7 @@ public class FilePageStore implements PageStore {
 
         long off = allocPage();
 
-        return off / pageSize;
+        return (off - headerSize()) / pageSize;
     }
 
     /**
@@ -519,6 +535,6 @@ public class FilePageStore implements PageStore {
         if (!inited)
             return 0;
 
-        return (int)(allocated.get() / pageSize);
+        return (int)(allocated.get() - headerSize()) / pageSize;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
new file mode 100644
index 0000000..d97ab26
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreFactory.java
@@ -0,0 +1,35 @@
+/*
+* 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.persistence.file;
+
+import java.io.File;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.pagemem.PageIdAllocator;
+
+/**
+ *
+ */
+public interface FilePageStoreFactory {
+    /**
+     * Creates instance of FilePageStore based on given file.
+     *
+     * @param type Data type, can be {@link PageIdAllocator#FLAG_IDX} or {@link PageIdAllocator#FLAG_DATA}.
+     * @param file File Page store file.
+     */
+    public FilePageStore createPageStore(byte type, File file) throws IgniteCheckedException;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
index e2ad070..0041ea6 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreManager.java
@@ -365,21 +365,16 @@ public class FilePageStoreManager extends GridCacheSharedManagerAdapter implemen
         if (dirExisted && !idxFile.exists())
             grpsWithoutIdx.add(grpDesc.groupId());
 
-        FilePageStore idxStore = new FilePageStore(
-            PageMemory.FLAG_IDX,
-            idxFile,
-            pstCfg.getFileIOFactory(),
-            cctx.kernalContext().config().getMemoryConfiguration());
+        FileVersionCheckingFactory pageStoreFactory = new FileVersionCheckingFactory(
+            pstCfg.getFileIOFactory(), igniteCfg.getMemoryConfiguration());
+
+        FilePageStore idxStore = pageStoreFactory.createPageStore(PageMemory.FLAG_IDX, idxFile);
 
         FilePageStore[] partStores = new FilePageStore[grpDesc.config().getAffinity().partitions()];
 
         for (int partId = 0; partId < partStores.length; partId++) {
-            FilePageStore partStore = new FilePageStore(
-                PageMemory.FLAG_DATA,
-                new File(cacheWorkDir, String.format(PART_FILE_TEMPLATE, partId)),
-                pstCfg.getFileIOFactory(),
-                cctx.kernalContext().config().getMemoryConfiguration()
-            );
+            FilePageStore partStore = pageStoreFactory.createPageStore(
+                PageMemory.FLAG_DATA, new File(cacheWorkDir, String.format(PART_FILE_TEMPLATE, partId)));
 
             partStores[partId] = partStore;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java
new file mode 100644
index 0000000..5d044ec
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FilePageStoreV2.java
@@ -0,0 +1,53 @@
+/*
+* 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.persistence.file;
+
+import java.io.File;
+import org.apache.ignite.configuration.MemoryConfiguration;
+
+/**
+ *
+ */
+public class FilePageStoreV2 extends FilePageStore {
+    /** File version. */
+    public static final int VERSION = 2;
+
+    /** Header size. */
+    private final int hdrSize;
+
+    /**
+     * @param type Type.
+     * @param file File.
+     * @param factory Factory.
+     * @param cfg Config.
+     */
+    public FilePageStoreV2(byte type, File file, FileIOFactory factory, MemoryConfiguration cfg) {
+        super(type, file, factory, cfg);
+
+        hdrSize = cfg.getPageSize();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int headerSize() {
+        return hdrSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int version() {
+        return VERSION;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
new file mode 100644
index 0000000..53bd802
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileVersionCheckingFactory.java
@@ -0,0 +1,116 @@
+/*
+* 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.persistence.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.configuration.MemoryConfiguration;
+
+/**
+ * Checks version in files if it's present on the disk, creates store with latest version otherwise.
+ */
+public class FileVersionCheckingFactory implements FilePageStoreFactory {
+    /** Property to override latest version. Should be used only in tests. */
+    public static final String LATEST_VERSION_OVERRIDE_PROPERTY = "file.page.store.latest.version.override";
+
+    /** Latest page store version. */
+    public final static int LATEST_VERSION = 2;
+
+    /** Factory to provide I/O interfaces for read/write operations with files. */
+    private final FileIOFactory fileIOFactory;
+
+    /** Memory configuration. */
+    private final MemoryConfiguration memCfg;
+
+    /**
+     * @param fileIOFactory File io factory.
+     * @param memCfg Memory configuration.
+     */
+    public FileVersionCheckingFactory(
+        FileIOFactory fileIOFactory, MemoryConfiguration memCfg) {
+        this.fileIOFactory = fileIOFactory;
+        this.memCfg = memCfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public FilePageStore createPageStore(byte type, File file) throws IgniteCheckedException {
+        if (!file.exists())
+            return createPageStore(type, file, latestVersion());
+
+        try (FileIO fileIO = fileIOFactory.create(file, "r")) {
+            int minHdr = FilePageStore.HEADER_SIZE;
+
+            if (fileIO.size() < minHdr)
+                return createPageStore(type, file, latestVersion());
+
+            ByteBuffer hdr = ByteBuffer.allocate(minHdr).order(ByteOrder.LITTLE_ENDIAN);
+
+            while (hdr.remaining() > 0)
+                fileIO.read(hdr);
+
+            hdr.rewind();
+
+            hdr.getLong(); // Read signature
+
+            int ver = hdr.getInt();
+
+            return createPageStore(type, file, ver);
+        }
+        catch (IOException e) {
+            throw new IgniteCheckedException("Error while creating file page store [file=" + file + "]:", e);
+        }
+    }
+
+    /**
+     * Resolves latest page store version.
+     */
+    public int latestVersion() {
+        int latestVer = LATEST_VERSION;
+
+        try {
+            latestVer = Integer.parseInt(System.getProperty(LATEST_VERSION_OVERRIDE_PROPERTY));
+        } catch (NumberFormatException e) {
+            // No override.
+        }
+
+        return latestVer;
+    }
+
+    /**
+     * Instantiates specific version of FilePageStore.
+     *
+     * @param type Type.
+     * @param file File.
+     * @param ver Version.
+     */
+    public FilePageStore createPageStore(byte type, File file, int ver) throws IgniteCheckedException {
+        switch (ver) {
+            case FilePageStore.VERSION:
+                return new FilePageStore(type, file, fileIOFactory, memCfg);
+
+            case FilePageStoreV2.VERSION:
+                return new FilePageStoreV2(type, file, fileIOFactory, memCfg);
+
+            default:
+                throw new IllegalArgumentException("Unknown version of file page store: " + ver);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/2f38065c/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
index c248c35..11d5eef 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgnitePdsRecoveryAfterFileCorruptionTest.java
@@ -194,7 +194,7 @@ public class IgnitePdsRecoveryAfterFileCorruptionTest extends GridCommonAbstract
 
         long size = fileIO.size();
 
-        fileIO.write(ByteBuffer.allocate((int)size - FilePageStore.HEADER_SIZE), FilePageStore.HEADER_SIZE);
+        fileIO.write(ByteBuffer.allocate((int)size - filePageStore.headerSize()), filePageStore.headerSize());
 
         fileIO.force();
     }


[07/29] ignite git commit: IGNITE-5923: ODBC: SQLGetTypeInfo now works with SQL_ALL_TYPES

Posted by nt...@apache.org.
IGNITE-5923: ODBC: SQLGetTypeInfo now works with SQL_ALL_TYPES

(cherry picked from commit 48c914d)


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

Branch: refs/heads/ignite-5947
Commit: 0b3a9a7176f5ae44a96ecf700c8147193dfbf064
Parents: d1a74a4
Author: Igor Sapego <is...@gridgain.com>
Authored: Fri Aug 4 13:18:00 2017 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Fri Aug 4 17:46:10 2017 +0300

----------------------------------------------------------------------
 modules/platforms/cpp/odbc-test/Makefile.am     |   1 +
 .../cpp/odbc-test/include/complex_type.h        | 271 +++++++++----------
 .../cpp/odbc-test/project/vs/odbc-test.vcxproj  |   1 +
 .../project/vs/odbc-test.vcxproj.filters        |   3 +
 .../cpp/odbc-test/src/meta_queries_test.cpp     | 189 +++++++++++++
 modules/platforms/cpp/odbc/src/odbc.cpp         |   2 +-
 .../cpp/odbc/src/query/type_info_query.cpp      |   2 +-
 modules/platforms/cpp/odbc/src/statement.cpp    |   2 +-
 8 files changed, 332 insertions(+), 139 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/modules/platforms/cpp/odbc-test/Makefile.am
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/Makefile.am b/modules/platforms/cpp/odbc-test/Makefile.am
index 56ae56a..1d65468 100644
--- a/modules/platforms/cpp/odbc-test/Makefile.am
+++ b/modules/platforms/cpp/odbc-test/Makefile.am
@@ -61,6 +61,7 @@ ignite_odbc_tests_SOURCES = \
     src/column_test.cpp \
     src/configuration_test.cpp \
     src/row_test.cpp \
+    src/meta_queries_test.cpp \
     src/utility_test.cpp \
     src/queries_test.cpp \
     src/test_utils.cpp \

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/modules/platforms/cpp/odbc-test/include/complex_type.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/include/complex_type.h b/modules/platforms/cpp/odbc-test/include/complex_type.h
index 8a1bd59..ea01554 100644
--- a/modules/platforms/cpp/odbc-test/include/complex_type.h
+++ b/modules/platforms/cpp/odbc-test/include/complex_type.h
@@ -1,137 +1,136 @@
-/*
- * 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.
- */
-
-#ifndef _IGNITE_ODBC_TEST_COMPLEX_TYPE
-#define _IGNITE_ODBC_TEST_COMPLEX_TYPE
-
-#include <string>
-
-#include "ignite/ignite.h"
-#include "ignite/ignition.h"
-
-namespace ignite
-{
-    struct TestObject
-    {
-        TestObject() :
-            f1(412),
-            f2("Lorem ipsum")
-        {
-            // No-op.
-        }
-
-        int32_t f1;
-        std::string f2;
-    };
-
-    struct ComplexType
-    {
-        ComplexType() :
-            i32Field(0)
-        {
-            // No-op.
-        }
-
-        int32_t i32Field;
-        TestObject objField;
-        std::string strField;
-    };
-
-    bool operator==(TestObject const& lhs, TestObject const& rhs)
-    {
-        return lhs.f1 == rhs.f1 && lhs.f2 == rhs.f2;
-    }
-
-    bool operator==(ComplexType const& lhs, ComplexType const& rhs)
-    {
-        return lhs.i32Field == rhs.i32Field && lhs.objField == rhs.objField && lhs.strField == rhs.strField;
-    }
-
-    std::ostream& operator<<(std::ostream& str, TestObject const& obj)
-    {
-        str << "TestObject::f1: " << obj.f1
-            << "TestObject::f2: " << obj.f2;
-        return str;
-    }
-
-    std::ostream& operator<<(std::ostream& str, ComplexType const& obj)
+/*
+ * 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.
+ */
+
+#ifndef _IGNITE_ODBC_TEST_COMPLEX_TYPE
+#define _IGNITE_ODBC_TEST_COMPLEX_TYPE
+
+#include <string>
+
+#include "ignite/ignite.h"
+
+namespace ignite
+{
+    struct TestObject
     {
-        str << "ComplexType::i32Field: " << obj.i32Field
-            << "ComplexType::objField: " << obj.objField
-            << "ComplexType::strField: " << obj.strField;
-        return str;
-    }
-}
-
-namespace ignite
-{
-    namespace binary
-    {
-
-        IGNITE_BINARY_TYPE_START(ignite::TestObject)
-
-            typedef ignite::TestObject TestObject;
-
-            IGNITE_BINARY_GET_TYPE_ID_AS_HASH(TestObject)
-            IGNITE_BINARY_GET_TYPE_NAME_AS_IS(TestObject)
-            IGNITE_BINARY_GET_FIELD_ID_AS_HASH
-            IGNITE_BINARY_IS_NULL_FALSE(TestObject)
-            IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(TestObject)
-
-            static void Write(BinaryWriter& writer, const TestObject& obj)
-            {
-                writer.WriteInt32("f1", obj.f1);
-                writer.WriteString("f2", obj.f2);
-            }
-
-            static void Read(BinaryReader& reader, TestObject& dst)
-            {
-                dst.f1 = reader.ReadInt32("f1");
-                dst.f2 = reader.ReadString("f2");
-            }
-
-        IGNITE_BINARY_TYPE_END
-
-        IGNITE_BINARY_TYPE_START(ignite::ComplexType)
-
-            typedef ignite::ComplexType ComplexType;
-
-            IGNITE_BINARY_GET_TYPE_ID_AS_HASH(ComplexType)
-            IGNITE_BINARY_GET_TYPE_NAME_AS_IS(ComplexType)
-            IGNITE_BINARY_GET_FIELD_ID_AS_HASH
-            IGNITE_BINARY_IS_NULL_FALSE(ComplexType)
-            IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(ComplexType)
-
-            static void Write(BinaryWriter& writer, const ComplexType& obj)
-            {
-                writer.WriteInt32("i32Field", obj.i32Field);
-                writer.WriteObject("objField", obj.objField);
-                writer.WriteString("strField", obj.strField);
-            }
-
-            static void Read(BinaryReader& reader, ComplexType& dst)
-            {
-                dst.i32Field = reader.ReadInt32("i32Field");
-                dst.objField = reader.ReadObject<TestObject>("objField");
-                dst.strField = reader.ReadString("strField");
-            }
-
-        IGNITE_BINARY_TYPE_END
-    }
-};
-
-#endif // _IGNITE_ODBC_TEST_COMPLEX_TYPE
+        TestObject() :
+            f1(412),
+            f2("Lorem ipsum")
+        {
+            // No-op.
+        }
+
+        friend bool operator==(TestObject const& lhs, TestObject const& rhs)
+        {
+            return lhs.f1 == rhs.f1 && lhs.f2 == rhs.f2;
+        }
+
+        friend std::ostream& operator<<(std::ostream& str, TestObject const& obj)
+        {
+            str << "TestObject::f1: " << obj.f1
+                << "TestObject::f2: " << obj.f2;
+            return str;
+        }
+
+        int32_t f1;
+        std::string f2;
+    };
+
+    struct ComplexType
+    {
+        ComplexType() :
+            i32Field(0)
+        {
+            // No-op.
+        }
+
+        friend bool operator==(ComplexType const& lhs, ComplexType const& rhs)
+        {
+            return lhs.i32Field == rhs.i32Field && lhs.objField == rhs.objField && lhs.strField == rhs.strField;
+        }
+
+        friend std::ostream& operator<<(std::ostream& str, ComplexType const& obj)
+        {
+            str << "ComplexType::i32Field: " << obj.i32Field
+                << "ComplexType::objField: " << obj.objField
+                << "ComplexType::strField: " << obj.strField;
+            return str;
+        }
+
+        int32_t i32Field;
+        TestObject objField;
+        std::string strField;
+    };
+}
+
+namespace ignite
+{
+    namespace binary
+    {
+
+        IGNITE_BINARY_TYPE_START(ignite::TestObject)
+
+            typedef ignite::TestObject TestObject;
+
+            IGNITE_BINARY_GET_TYPE_ID_AS_HASH(TestObject)
+            IGNITE_BINARY_GET_TYPE_NAME_AS_IS(TestObject)
+            IGNITE_BINARY_GET_FIELD_ID_AS_HASH
+            IGNITE_BINARY_IS_NULL_FALSE(TestObject)
+            IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(TestObject)
+
+            static void Write(BinaryWriter& writer, const TestObject& obj)
+            {
+                writer.WriteInt32("f1", obj.f1);
+                writer.WriteString("f2", obj.f2);
+            }
+
+            static void Read(BinaryReader& reader, TestObject& dst)
+            {
+                dst.f1 = reader.ReadInt32("f1");
+                dst.f2 = reader.ReadString("f2");
+            }
+
+        IGNITE_BINARY_TYPE_END
+
+        IGNITE_BINARY_TYPE_START(ignite::ComplexType)
+
+            typedef ignite::ComplexType ComplexType;
+
+            IGNITE_BINARY_GET_TYPE_ID_AS_HASH(ComplexType)
+            IGNITE_BINARY_GET_TYPE_NAME_AS_IS(ComplexType)
+            IGNITE_BINARY_GET_FIELD_ID_AS_HASH
+            IGNITE_BINARY_IS_NULL_FALSE(ComplexType)
+            IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(ComplexType)
+
+            static void Write(BinaryWriter& writer, const ComplexType& obj)
+            {
+                writer.WriteInt32("i32Field", obj.i32Field);
+                writer.WriteObject("objField", obj.objField);
+                writer.WriteString("strField", obj.strField);
+            }
+
+            static void Read(BinaryReader& reader, ComplexType& dst)
+            {
+                dst.i32Field = reader.ReadInt32("i32Field");
+                dst.objField = reader.ReadObject<TestObject>("objField");
+                dst.strField = reader.ReadString("strField");
+            }
+
+        IGNITE_BINARY_TYPE_END
+    }
+};
+
+#endif // _IGNITE_ODBC_TEST_COMPLEX_TYPE

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/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 c332aad..ceecb3d 100644
--- a/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
+++ b/modules/platforms/cpp/odbc-test/project/vs/odbc-test.vcxproj
@@ -168,6 +168,7 @@
     <ClCompile Include="..\..\src\configuration_test.cpp" />
     <ClCompile Include="..\..\src\connection_info_test.cpp" />
     <ClCompile Include="..\..\src\cursor_test.cpp" />
+    <ClCompile Include="..\..\src\meta_queries_test.cpp" />
     <ClCompile Include="..\..\src\queries_test.cpp" />
     <ClCompile Include="..\..\src\parser_test.cpp" />
     <ClCompile Include="..\..\src\row_test.cpp" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/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 65f2ebf..91c029e 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
@@ -121,6 +121,9 @@
     <ClCompile Include="..\..\..\odbc\src\log.cpp">
       <Filter>Externals</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\meta_queries_test.cpp">
+      <Filter>Code</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\include\test_type.h">

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
new file mode 100644
index 0000000..5b7ae59
--- /dev/null
+++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+#   include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#ifndef _MSC_VER
+#   define BOOST_TEST_DYN_LINK
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+#include "ignite/ignition.h"
+
+#include "ignite/common/fixed_size_array.h"
+#include "ignite/impl/binary/binary_utils.h"
+
+#include "test_type.h"
+#include "complex_type.h"
+#include "test_utils.h"
+
+using namespace ignite;
+using namespace ignite::cache;
+using namespace ignite::cache::query;
+using namespace ignite::common;
+using namespace ignite_test;
+using namespace ignite::binary;
+using namespace ignite::impl::binary;
+using namespace ignite::impl::interop;
+
+using namespace boost::unit_test;
+
+/**
+ * Test setup fixture.
+ */
+struct MetaQueriesTestSuiteFixture 
+{
+    /**
+     * Establish connection to node.
+     *
+     * @param connectStr Connection string.
+     */
+    void Connect(const std::string& connectStr)
+    {
+        // Allocate an environment handle
+        SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
+
+        BOOST_REQUIRE(env != NULL);
+
+        // We want ODBC 3 support
+        SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(SQL_OV_ODBC3), 0);
+
+        // Allocate a connection handle
+        SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
+
+        BOOST_REQUIRE(dbc != NULL);
+
+        // Connect string
+        std::vector<SQLCHAR> connectStr0;
+
+        connectStr0.reserve(connectStr.size() + 1);
+        std::copy(connectStr.begin(), connectStr.end(), std::back_inserter(connectStr0));
+
+        SQLCHAR outstr[ODBC_BUFFER_SIZE];
+        SQLSMALLINT outstrlen;
+
+        // Connecting to ODBC server.
+        SQLRETURN ret = SQLDriverConnect(dbc, NULL, &connectStr0[0], static_cast<SQLSMALLINT>(connectStr0.size()),
+            outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE);
+
+        if (!SQL_SUCCEEDED(ret))
+        {
+            Ignition::Stop(grid.GetName(), true);
+
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_DBC, dbc));
+        }
+
+        // Allocate a statement handle
+        SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+
+        BOOST_REQUIRE(stmt != NULL);
+    }
+
+    void Disconnect()
+    {
+        // Releasing statement handle.
+        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+
+        // Disconneting from the server.
+        SQLDisconnect(dbc);
+
+        // Releasing allocated handles.
+        SQLFreeHandle(SQL_HANDLE_DBC, dbc);
+        SQLFreeHandle(SQL_HANDLE_ENV, env);
+    }
+
+    static Ignite StartAdditionalNode(const char* name)
+    {
+#ifdef IGNITE_TESTS_32
+        return StartNode("queries-test-noodbc-32.xml", name);
+#else
+        return StartNode("queries-test-noodbc.xml", name);
+#endif
+    }
+
+    /**
+     * Constructor.
+     */
+    MetaQueriesTestSuiteFixture() :
+        cache1(0),
+        cache2(0),
+        env(NULL),
+        dbc(NULL),
+        stmt(NULL)
+    {
+#ifdef IGNITE_TESTS_32
+        grid = StartNode("queries-test-32.xml", "NodeMain");
+#else
+        grid = StartNode("queries-test.xml", "NodeMain");
+#endif
+
+        cache1 = grid.GetCache<int64_t, TestType>("cache");
+        cache2 = grid.GetCache<int64_t, ComplexType>("cache2");
+    }
+
+    /**
+     * Destructor.
+     */
+    ~MetaQueriesTestSuiteFixture()
+    {
+        Disconnect();
+
+        Ignition::StopAll(true);
+    }
+
+    /** Node started during the test. */
+    Ignite grid;
+
+    /** Frist cache instance. */
+    Cache<int64_t, TestType> cache1;
+
+    /** Second cache instance. */
+    Cache<int64_t, ComplexType> cache2;
+
+    /** ODBC Environment. */
+    SQLHENV env;
+
+    /** ODBC Connect. */
+    SQLHDBC dbc;
+
+    /** ODBC Statement. */
+    SQLHSTMT stmt;
+};
+
+BOOST_FIXTURE_TEST_SUITE(MetaQueriesTestSuite, MetaQueriesTestSuiteFixture)
+
+BOOST_AUTO_TEST_CASE(TestGetTypeInfoAllTypes)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLRETURN ret = SQLGetTypeInfo(stmt, SQL_ALL_TYPES);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+}
+
+BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/modules/platforms/cpp/odbc/src/odbc.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp
index b450903..1862465 100644
--- a/modules/platforms/cpp/odbc/src/odbc.cpp
+++ b/modules/platforms/cpp/odbc/src/odbc.cpp
@@ -1019,7 +1019,7 @@ namespace ignite
     {
         using odbc::Statement;
 
-        LOG_MSG("SQLGetTypeInfo called");
+        LOG_MSG("SQLGetTypeInfo called: [type=" << type << ']');
 
         Statement *statement = reinterpret_cast<Statement*>(stmt);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/type_info_query.cpp b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
index 280477b..f6b3990 100644
--- a/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
+++ b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
@@ -155,7 +155,7 @@ namespace ignite
                 columnsMeta.push_back(ColumnMeta(sch, tbl, "NUM_PREC_RADIX",     IGNITE_TYPE_INT));
                 columnsMeta.push_back(ColumnMeta(sch, tbl, "INTERVAL_PRECISION", IGNITE_TYPE_SHORT));
 
-                assert(IsSqlTypeSupported(sqlType));
+                assert(IsSqlTypeSupported(sqlType) || sqlType == SQL_ALL_TYPES);
 
                 if (sqlType == SQL_ALL_TYPES)
                 {

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b3a9a71/modules/platforms/cpp/odbc/src/statement.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/statement.cpp b/modules/platforms/cpp/odbc/src/statement.cpp
index adc7d6b..38a1e2e 100644
--- a/modules/platforms/cpp/odbc/src/statement.cpp
+++ b/modules/platforms/cpp/odbc/src/statement.cpp
@@ -671,7 +671,7 @@ namespace ignite
 
         SqlResult::Type Statement::InternalExecuteGetTypeInfoQuery(int16_t sqlType)
         {
-            if (!type_traits::IsSqlTypeSupported(sqlType))
+            if (sqlType != SQL_ALL_TYPES && !type_traits::IsSqlTypeSupported(sqlType))
             {
                 std::stringstream builder;
                 builder << "Data type is not supported. [typeId=" << sqlType << ']';


[26/29] ignite git commit: IGNITE-6004: Added QuerySqlField.inlineSize property. This closes #2420.

Posted by nt...@apache.org.
IGNITE-6004: Added QuerySqlField.inlineSize property. This closes #2420.


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

Branch: refs/heads/ignite-5947
Commit: 621380dbec5d1b9dcff626bb1686ad75361f7ed8
Parents: 305c0f4
Author: tledkov-gridgain <tl...@gridgain.com>
Authored: Tue Aug 15 11:19:37 2017 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Tue Aug 15 11:20:56 2017 +0300

----------------------------------------------------------------------
 .../org/apache/ignite/cache/QueryEntity.java    |  15 +-
 .../org/apache/ignite/cache/QueryIndex.java     |   5 +-
 .../query/annotations/QueryGroupIndex.java      |  20 +++
 .../cache/query/annotations/QuerySqlField.java  |  23 +++
 .../cache/query/QueryEntityTypeDescriptor.java  |  17 +-
 ...ridCacheQuerySqlFieldInlineSizeSelfTest.java | 160 +++++++++++++++++++
 .../IgniteCacheQuerySelfTestSuite.java          |   3 +
 7 files changed, 226 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
index 5180100..6440b48 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryEntity.java
@@ -419,6 +419,7 @@ public class QueryEntity implements Serializable {
                 sortedIdx.setFields(fields);
 
                 sortedIdx.setName(idxEntry.getKey());
+                sortedIdx.setInlineSize(idx.inlineSize());
 
                 idxs.add(sortedIdx);
             }
@@ -480,7 +481,7 @@ public class QueryEntity implements Serializable {
                 String idxName = cls.getSimpleName() + "_" + QueryUtils.VAL_FIELD_NAME + "_idx";
 
                 type.addIndex(idxName, QueryUtils.isGeometryClass(cls) ?
-                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
+                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED, QueryIndex.DFLT_INLINE_SIZE);
 
                 type.addFieldToIndex(idxName, QueryUtils.VAL_FIELD_NAME, 0, false);
             }
@@ -500,13 +501,13 @@ public class QueryEntity implements Serializable {
             QueryGroupIndex grpIdx = cls.getAnnotation(QueryGroupIndex.class);
 
             if (grpIdx != null)
-                type.addIndex(grpIdx.name(), QueryIndexType.SORTED);
+                type.addIndex(grpIdx.name(), QueryIndexType.SORTED, grpIdx.inlineSize());
 
             QueryGroupIndex.List grpIdxList = cls.getAnnotation(QueryGroupIndex.List.class);
 
             if (grpIdxList != null && !F.isEmpty(grpIdxList.value())) {
                 for (QueryGroupIndex idx : grpIdxList.value())
-                    type.addIndex(idx.name(), QueryIndexType.SORTED);
+                    type.addIndex(idx.name(), QueryIndexType.SORTED, idx.inlineSize());
             }
         }
 
@@ -559,11 +560,17 @@ public class QueryEntity implements Serializable {
                     idxName = cls.getSimpleName() + "_" + idxName;
 
                 desc.addIndex(idxName, QueryUtils.isGeometryClass(prop.type()) ?
-                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED);
+                    QueryIndexType.GEOSPATIAL : QueryIndexType.SORTED, sqlAnn.inlineSize());
 
                 desc.addFieldToIndex(idxName, prop.fullName(), 0, sqlAnn.descending());
             }
 
+            if ((!F.isEmpty(sqlAnn.groups()) || !F.isEmpty(sqlAnn.orderedGroups()))
+                && sqlAnn.inlineSize() != QueryIndex.DFLT_INLINE_SIZE) {
+                throw new CacheException("Inline size cannot be set on a field with group index [" +
+                    "type=" + cls.getName() + ", property=" + prop.fullName() + ']');
+            }
+
             if (!F.isEmpty(sqlAnn.groups())) {
                 for (String group : sqlAnn.groups())
                     desc.addFieldToIndex(group, prop.fullName(), 0, false);

http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java
index 6e73049..ac7dd8e 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/QueryIndex.java
@@ -38,6 +38,9 @@ public class QueryIndex implements Serializable {
     /** */
     private static final QueryIndexType DFLT_IDX_TYP = QueryIndexType.SORTED;
 
+    /** Default index inline size. */
+    public static final int DFLT_INLINE_SIZE = -1;
+
     /** Index name. */
     private String name;
 
@@ -49,7 +52,7 @@ public class QueryIndex implements Serializable {
     private QueryIndexType type = DFLT_IDX_TYP;
 
     /** */
-    private int inlineSize = -1;
+    private int inlineSize = DFLT_INLINE_SIZE;
 
     /**
      * Creates an empty index. Should be populated via setters.

http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QueryGroupIndex.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QueryGroupIndex.java b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QueryGroupIndex.java
index b1fefae..a947d0f 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QueryGroupIndex.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QueryGroupIndex.java
@@ -21,6 +21,8 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.configuration.CacheConfiguration;
 
 /**
  * Describes group index.
@@ -36,6 +38,24 @@ public @interface QueryGroupIndex {
     String name();
 
     /**
+     * Index inline size in bytes. When enabled part of indexed value will be placed directly to index pages,
+     * thus minimizing data page accesses, thus incraesing query performance.
+     * <p>
+     * Allowed values:
+     * <ul>
+     *     <li>{@code -1} (default) - determine inline size automatically (see below)</li>
+     *     <li>{@code 0} - index inline is disabled (not recommended)</li>
+     *     <li>positive value - fixed index inline</li>
+     * </ul>
+     * When set to {@code -1}, Ignite will try to detect inline size automatically. It will be no more than
+     * {@link CacheConfiguration#getSqlIndexMaxInlineSize()}. Index inline will be enabled for all fixed-length types,
+     * but <b>will not be enabled</b> for {@code String}.
+     *
+     * @return Index inline size in bytes.
+     */
+    int inlineSize() default QueryIndex.DFLT_INLINE_SIZE;
+
+    /**
      * List of group indexes for type.
      */
     @SuppressWarnings("PublicInnerClass")

http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java
index 94dbea1..64aaa3a 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/query/annotations/QuerySqlField.java
@@ -22,6 +22,8 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.processors.cache.query.CacheQuery;
 
 /**
@@ -88,6 +90,27 @@ public @interface QuerySqlField {
     String name() default "";
 
     /**
+     * Index inline size in bytes. When enabled part of indexed value will be placed directly to index pages,
+     * thus minimizing data page accesses, thus incraesing query performance.
+     * <p>
+     * Allowed values:
+     * <ul>
+     *     <li>{@code -1} (default) - determine inline size automatically (see below)</li>
+     *     <li>{@code 0} - index inline is disabled (not recommended)</li>
+     *     <li>positive value - fixed index inline</li>
+     * </ul>
+     * When set to {@code -1}, Ignite will try to detect inline size automatically. It will be no more than
+     * {@link CacheConfiguration#getSqlIndexMaxInlineSize()}. Index inline will be enabled for all fixed-length types,
+     * but <b>will not be enabled</b> for {@code String}.
+     * <p>
+     * When index group is used, inline size must be defined in {@link QueryGroupIndex#inlineSize()}. Any value
+     * except of {@code -1} defined on a specific column will lead to exception.
+     *
+     * @return Index inline size in bytes.
+     */
+    int inlineSize() default QueryIndex.DFLT_INLINE_SIZE;
+
+    /**
      * Describes group of index and position of field in this group.
      * <p>
      * Opposite to {@link #groups()} this annotation gives control over order of fields in a group index.

http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
index 47ab263..837a08f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/QueryEntityTypeDescriptor.java
@@ -24,6 +24,7 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 import javax.cache.CacheException;
+import org.apache.ignite.cache.QueryIndex;
 import org.apache.ignite.cache.QueryIndexType;
 import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
@@ -78,6 +79,9 @@ public class QueryEntityTypeDescriptor {
      * @return Index descriptor.
      */
     public QueryEntityIndexDescriptor addIndex(String idxName, QueryIndexType type, int inlineSize) {
+        if (inlineSize < 0 && inlineSize != QueryIndex.DFLT_INLINE_SIZE)
+            throw new CacheException("Illegal inline size [idxName=" + idxName + ", inlineSize=" + inlineSize + ']');
+
         QueryEntityIndexDescriptor idx = new QueryEntityIndexDescriptor(type, inlineSize);
 
         if (indexes.put(idxName, idx) != null)
@@ -87,17 +91,6 @@ public class QueryEntityTypeDescriptor {
     }
 
     /**
-     * Adds index.
-     *
-     * @param idxName Index name.
-     * @param type Index type.
-     * @return Index descriptor.
-     */
-    public QueryEntityIndexDescriptor addIndex(String idxName, QueryIndexType type) {
-        return addIndex(idxName, type, -1);
-    }
-
-    /**
      * Adds field to index.
      *
      * @param idxName Index name.
@@ -110,7 +103,7 @@ public class QueryEntityTypeDescriptor {
         QueryEntityIndexDescriptor desc = indexes.get(idxName);
 
         if (desc == null)
-            desc = addIndex(idxName, QueryIndexType.SORTED);
+            desc = addIndex(idxName, QueryIndexType.SORTED, QueryIndex.DFLT_INLINE_SIZE);
 
         desc.addField(field, orderNum, descending);
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQuerySqlFieldInlineSizeSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQuerySqlFieldInlineSizeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQuerySqlFieldInlineSizeSelfTest.java
new file mode 100644
index 0000000..a257160
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQuerySqlFieldInlineSizeSelfTest.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.concurrent.Callable;
+import javax.cache.CacheException;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.query.annotations.QueryGroupIndex;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Tests cache configuration with inlineSize property of the QuerySqlField annotation.
+ */
+@SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "unchecked", "unused"})
+public class GridCacheQuerySqlFieldInlineSizeSelfTest extends GridCommonAbstractTest {
+    /**
+     * @throws Exception If failed.
+     */
+    public void testSingleFieldIndexes() throws Exception {
+        CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        ccfg.setIndexedTypes(Integer.class, TestValueSingleFieldIndexes.class);
+
+        assertEquals(1, ccfg.getQueryEntities().size());
+
+        QueryEntity ent = (QueryEntity)ccfg.getQueryEntities().iterator().next();
+
+        assertEquals(2, ent.getIndexes().size());
+
+        for (QueryIndex idx : ent.getIndexes()) {
+            if(idx.getFields().containsKey("val0"))
+                assertEquals(10, idx.getInlineSize());
+            else if(idx.getFields().containsKey("val1"))
+                assertEquals(20, idx.getInlineSize());
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testGroupIndex() throws Exception {
+        CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        ccfg.setIndexedTypes(Integer.class, TestValueGroupIndex.class);
+
+        assertEquals(1, ccfg.getQueryEntities().size());
+
+        QueryEntity ent = (QueryEntity)ccfg.getQueryEntities().iterator().next();
+
+        assertEquals(1, ent.getIndexes().size());
+
+        QueryIndex idx = ent.getIndexes().iterator().next();
+
+        assertEquals(10, idx.getInlineSize());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testGroupIndexInvalidAnnotaion() throws Exception {
+        final CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                ccfg.setIndexedTypes(Integer.class, TestValueGroupIndexInvalidAnnotation.class);
+
+                return null;
+            }
+        }, CacheException.class, "Inline size cannot be set on a field with group index");
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testNegativeInlineSize() throws Exception {
+        final CacheConfiguration ccfg = defaultCacheConfiguration();
+
+        GridTestUtils.assertThrows(
+            log, new Callable<Object>() {
+
+                @Override public Object call() throws Exception {
+                    ccfg.setIndexedTypes(Integer.class, TestValueNegativeInlineSize.class);
+
+                    return null;
+                }
+            },
+            CacheException.class,
+            "Illegal inline size [idxName=TestValueNegativeInlineSize_val_idx, inlineSize=-10]"
+        );
+    }
+
+    /**
+     *
+     */
+    static class TestValueSingleFieldIndexes {
+        /** */
+        @QuerySqlField(index = true, inlineSize = 10)
+        String val0;
+
+        /** */
+        @QuerySqlField(index = true, inlineSize = 20)
+        String val1;
+    }
+
+    /**
+     *
+     */
+    @QueryGroupIndex(name="idx", inlineSize = 10)
+    static class TestValueGroupIndex {
+        /** */
+        @QuerySqlField(orderedGroups = @QuerySqlField.Group(name = "idx", order = 0))
+        String val0;
+
+        /** */
+        @QuerySqlField(orderedGroups = @QuerySqlField.Group(name = "idx", order = 1))
+        String val1;
+    }
+
+    /**
+     *
+     */
+    @QueryGroupIndex(name="idx")
+    static class TestValueGroupIndexInvalidAnnotation {
+        /** */
+        @QuerySqlField(orderedGroups = @QuerySqlField.Group(name = "idx", order = 0))
+        String val0;
+
+        /** */
+        @QuerySqlField(orderedGroups = @QuerySqlField.Group(name = "idx", order = 1), inlineSize = 10)
+        String val1;
+    }
+
+    /**
+     *
+     */
+    static class TestValueNegativeInlineSize {
+         /** */
+         @QuerySqlField(index = true, inlineSize = -10)
+         String val;
+     }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/621380db/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
index decc7d5..99b0370 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
@@ -39,6 +39,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheQueryIndexDisabledSe
 import org.apache.ignite.internal.processors.cache.GridCacheQueryIndexingDisabledSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheQueryInternalKeysSelfTest;
 import org.apache.ignite.internal.processors.cache.GridCacheQuerySerializationSelfTest;
+import org.apache.ignite.internal.processors.cache.GridCacheQuerySqlFieldInlineSizeSelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteBinaryObjectFieldsQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.IgniteBinaryObjectLocalQueryArgumentsTest;
 import org.apache.ignite.internal.processors.cache.IgniteBinaryObjectQueryArgumentsTest;
@@ -320,6 +321,8 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
         suite.addTestSuite(IgniteSqlRoutingTest.class);
         suite.addTestSuite(LongIndexNameTest.class);
 
+        suite.addTestSuite(GridCacheQuerySqlFieldInlineSizeSelfTest.class);
+
         return suite;
     }
 }


[02/29] ignite git commit: IGNITE-4800: Lucene query may fails with NPE. Test fixed.

Posted by nt...@apache.org.
IGNITE-4800: Lucene query may fails with NPE.
Test fixed.


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

Branch: refs/heads/ignite-5947
Commit: 3fdf453e89a7bd76dff6b6d0646e3821ea3921d5
Parents: 1e08c3f
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Mon Jul 31 17:32:12 2017 +0300
Committer: Andrey V. Mashenkov <an...@gmail.com>
Committed: Mon Jul 31 17:32:12 2017 +0300

----------------------------------------------------------------------
 .../cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java    | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/3fdf453e/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
index ed092df..162b1e5 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheFullTextQueryNodeJoiningSelfTest.java
@@ -42,7 +42,6 @@ import static org.apache.ignite.cache.CacheMode.PARTITIONED;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 
 /**
- * TODO https://issues.apache.org/jira/browse/IGNITE-2229
  * Tests cache in-place modification logic with iterative value increment.
  */
 public class IgniteCacheFullTextQueryNodeJoiningSelfTest extends GridCommonAbstractTest {
@@ -107,6 +106,8 @@ public class IgniteCacheFullTextQueryNodeJoiningSelfTest extends GridCommonAbstr
      * @throws Exception If failed.
      */
     public void testFullTextQueryNodeJoin() throws Exception {
+        fail("https://issues.apache.org/jira/browse/IGNITE-2229");
+
         for (int r = 0; r < 5; r++) {
             startGrids(GRID_CNT);
 
@@ -119,10 +120,6 @@ public class IgniteCacheFullTextQueryNodeJoiningSelfTest extends GridCommonAbstr
 
                 Ignite started = startGrid(GRID_CNT);
 
-                //TODO: remove next line when IGNITE-2229 issue will be fixed.
-                // see https://issues.apache.org/jira/browse/IGNITE-2229
-                awaitPartitionMapExchange();
-
                 for (int i = 0; i < 100; i++) {
                     QueryCursor<Cache.Entry<AffinityKey<Integer>, IndexedEntity>> res = started.cache(DEFAULT_CACHE_NAME)
                         .query(new TextQuery<AffinityKey<Integer>, IndexedEntity>(IndexedEntity.class, "indexed"));


[20/29] ignite git commit: IGNITE-5941 - Fixed index name length restrictions. This closes #2408

Posted by nt...@apache.org.
IGNITE-5941 - Fixed index name length restrictions. This closes #2408


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

Branch: refs/heads/ignite-5947
Commit: fde550bac56fd0cc7c51c62a9c291dd4c3f3030c
Parents: 74d6ab9
Author: Ilya Lantukh <il...@gridgain.com>
Authored: Mon Aug 14 11:32:11 2017 +0300
Committer: Alexey Goncharuk <al...@gmail.com>
Committed: Mon Aug 14 11:33:34 2017 +0300

----------------------------------------------------------------------
 .../ignite/internal/pagemem/PageUtils.java      |  26 +++
 .../cache/persistence/MetadataStorage.java      |  12 +-
 .../cache/index/LongIndexNameTest.java          | 212 +++++++++++++++++++
 .../IgniteCacheQuerySelfTestSuite.java          |   2 +
 4 files changed, 246 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/fde550ba/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageUtils.java
index 3fa5954..362ac54 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/PageUtils.java
@@ -37,6 +37,19 @@ public class PageUtils {
     }
 
     /**
+     *
+     * @param addr Start address.
+     * @param off Offset.
+     * @return Byte value from given address.
+     */
+    public static int getUnsignedByte(long addr, int off) {
+        assert addr > 0 : addr;
+        assert off >= 0;
+
+        return GridUnsafe.getByte(addr + off) & 0xFF;
+    }
+
+    /**
      * @param addr Start address.
      * @param off Offset.
      * @param len Bytes length.
@@ -168,6 +181,19 @@ public class PageUtils {
      * @param off Offset.
      * @param v Value.
      */
+    public static void putUnsignedByte(long addr, int off, int v) {
+        assert addr > 0 : addr;
+        assert off >= 0;
+        assert v >= 0 && v <= 255;
+
+        GridUnsafe.putByte(addr + off, (byte) v);
+    }
+
+    /**
+     * @param addr Address.
+     * @param off Offset.
+     * @param v Value.
+     */
     public static void putShort(long addr, int off, short v) {
         assert addr > 0 : addr;
         assert off >= 0;

http://git-wip-us.apache.org/repos/asf/ignite/blob/fde550ba/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
index 743f3b9..498ecdd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
@@ -39,7 +39,7 @@ import org.apache.ignite.internal.util.typedef.internal.U;
  */
 public class MetadataStorage implements MetaStore {
     /** Max index name length (bytes num) */
-    public static final int MAX_IDX_NAME_LEN = 768;
+    public static final int MAX_IDX_NAME_LEN = 255;
 
     /** Bytes in byte. */
     private static final int BYTE_LEN = 1;
@@ -197,7 +197,7 @@ public class MetadataStorage implements MetaStore {
             int shift = 0;
 
             // Compare index names.
-            final byte len = PageUtils.getByte(pageAddr, off + shift);
+            final int len = PageUtils.getUnsignedByte(pageAddr, off + shift);
 
             shift += BYTE_LEN;
 
@@ -256,7 +256,7 @@ public class MetadataStorage implements MetaStore {
         final IndexItem row
     ) {
         // Index name length.
-        PageUtils.putByte(pageAddr, off, (byte)row.idxName.length);
+        PageUtils.putUnsignedByte(pageAddr, off, row.idxName.length);
         off++;
 
         // Index name.
@@ -282,10 +282,10 @@ public class MetadataStorage implements MetaStore {
         int srcOff
     ) {
         // Index name length.
-        final byte len = PageUtils.getByte(srcPageAddr, srcOff);
+        final int len = PageUtils.getUnsignedByte(srcPageAddr, srcOff);
         srcOff++;
 
-        PageUtils.putByte(dstPageAddr, dstOff, len);
+        PageUtils.putUnsignedByte(dstPageAddr, dstOff, len);
         dstOff++;
 
         PageHandler.copyMemory(srcPageAddr, dstPageAddr, srcOff, dstOff, len);
@@ -305,7 +305,7 @@ public class MetadataStorage implements MetaStore {
      */
     private static IndexItem readRow(final long pageAddr, int off) {
         // Index name length.
-        final int len = PageUtils.getByte(pageAddr, off) & 0xFF;
+        final int len = PageUtils.getUnsignedByte(pageAddr, off) & 0xFF;
         off++;
 
         // Index name.

http://git-wip-us.apache.org/repos/asf/ignite/blob/fde550ba/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/LongIndexNameTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/LongIndexNameTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/LongIndexNameTest.java
new file mode 100644
index 0000000..92883a4
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/LongIndexNameTest.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.index;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.QueryIndex;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cache.query.QueryCursor;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.PersistentStoreConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ *
+ */
+public class LongIndexNameTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        return super.getConfiguration(igniteInstanceName)
+            .setPersistentStoreConfiguration(new PersistentStoreConfiguration())
+            .setCacheConfiguration(new <String, Person>CacheConfiguration("cache")
+                .setQueryEntities(getIndexCfg())
+                .setAffinity(new RendezvousAffinityFunction(false, 16)));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        deleteWorkFiles();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        deleteWorkFiles();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testLongIndexNames() throws Exception {
+        try {
+            Ignite ignite = startGrid(0);
+
+            IgniteCache cache = insertSomeData(ignite);
+
+            QueryCursor cursor1 = cache.query(new SqlFieldsQuery("SELECT * FROM Person where name like '%Name 0'"));
+            QueryCursor cursor1Idx = cache.query(new SqlFieldsQuery("SELECT * FROM Person where name = 'Name 0'"));
+
+            QueryCursor cursor2 = cache.query(new SqlFieldsQuery("SELECT * FROM Person where age like '%0'"));
+            QueryCursor cursor2Idx = cache.query(new SqlFieldsQuery("SELECT * FROM Person where age = 0"));
+
+            assertEquals(cursor1.getAll().size(), cursor1Idx.getAll().size());
+            assertEquals(cursor2.getAll().size(), cursor2Idx.getAll().size());
+
+            ignite.close();
+
+            Thread.sleep(2_000);
+
+            ignite = startGrid(0);
+
+            cache = insertSomeData(ignite);
+
+            cursor1 = cache.query(new SqlFieldsQuery("SELECT * FROM Person where name like '%Name 0'"));
+            cursor1Idx = cache.query(new SqlFieldsQuery("SELECT * FROM Person where name = 'Name 0'"));
+
+            cursor2 = cache.query(new SqlFieldsQuery("SELECT * FROM Person where age like '%0'"));
+            cursor2Idx = cache.query(new SqlFieldsQuery("SELECT * FROM Person where age = 0"));
+
+            assertEquals(cursor1.getAll().size(), cursor1Idx.getAll().size());
+            assertEquals(cursor2.getAll().size(), cursor2Idx.getAll().size());
+
+
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /**
+     *
+     */
+    @NotNull private IgniteCache insertSomeData(Ignite ignite) {
+        if (!ignite.active())
+            ignite.active(true);
+
+        IgniteCache<String, Person> cache = ignite.cache("cache");
+
+        for (int i=0; i<10; i++)
+            cache.put(String.valueOf(System.currentTimeMillis()), new Person("Name " + i, i));
+
+        return cache;
+    }
+
+    /**
+     *
+     */
+    public static List<QueryEntity> getIndexCfg() {
+        ArrayList<QueryEntity> entities = new ArrayList<>();
+
+        QueryEntity qe = new QueryEntity(String.class.getName(), Person.class.getName());
+
+        LinkedHashMap<String, String> fieldsMap = new LinkedHashMap<>();
+        fieldsMap.put("name", String.class.getName());
+        fieldsMap.put("age", Integer.class.getName());
+
+        qe.setFields(fieldsMap);
+
+        ArrayList<QueryIndex> indices = new ArrayList<>();
+        QueryIndex index = new QueryIndex("name", true, "LONG_NAME_123456789012345678901234567890" +
+            "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+
+        QueryIndex index2 = new QueryIndex("age", true, "AGE_IDX");
+        indices.add(index);
+        indices.add(index2);
+
+        qe.setIndexes(indices);
+
+        entities.add(qe);
+
+        return entities;
+    }
+
+    /**
+     * @throws IgniteCheckedException If failed.
+     */
+    private void deleteWorkFiles() throws IgniteCheckedException {
+        deleteRecursively(U.resolveWorkDirectory(U.defaultWorkDirectory(), "db", false));
+    }
+
+    /**
+     *
+     */
+    private static class Person {
+        /** */
+        private String name;
+
+        /** */
+        private int age;
+
+        /**
+         *
+         */
+        public Person() {
+            // No-op.
+        }
+
+        /**
+         * @param name Name.
+         * @param age Age.
+         */
+        public Person(String name, int age) {
+            this.name = name;
+            this.age = age;
+        }
+
+        /**
+         * @return Name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name Name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * @return Age.
+         */
+        public int getAge() {
+            return age;
+        }
+
+        /**
+         * @param age Age.
+         */
+        public void setAge(int age) {
+            this.age = age;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/fde550ba/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
index 1ad0d4b..decc7d5 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
@@ -108,6 +108,7 @@ import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComple
 import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerTransactionalPartitionedTest;
 import org.apache.ignite.internal.processors.cache.index.H2DynamicIndexingComplexServerTransactionalReplicatedTest;
 import org.apache.ignite.internal.processors.cache.index.H2DynamicTableSelfTest;
+import org.apache.ignite.internal.processors.cache.index.LongIndexNameTest;
 import org.apache.ignite.internal.processors.cache.index.SchemaExchangeSelfTest;
 import org.apache.ignite.internal.processors.cache.local.IgniteCacheLocalAtomicQuerySelfTest;
 import org.apache.ignite.internal.processors.cache.local.IgniteCacheLocalFieldsQuerySelfTest;
@@ -317,6 +318,7 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
         suite.addTestSuite(IgniteCacheDistributedPartitionQueryConfigurationSelfTest.class);
         suite.addTestSuite(IgniteSqlKeyValueFieldsTest.class);
         suite.addTestSuite(IgniteSqlRoutingTest.class);
+        suite.addTestSuite(LongIndexNameTest.class);
 
         return suite;
     }


[16/29] ignite git commit: IGNITE-5902 Implemented stop caches at once. (cherry picked from commit ebb8765)

Posted by nt...@apache.org.
IGNITE-5902 Implemented stop caches at once.
(cherry picked from commit ebb8765)


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

Branch: refs/heads/ignite-5947
Commit: 5c2097856714a7803956d754735c68b21156019c
Parents: 841db65
Author: Alexey Kuznetsov <ak...@apache.org>
Authored: Fri Aug 11 10:25:36 2017 +0700
Committer: Alexey Kuznetsov <ak...@apache.org>
Committed: Fri Aug 11 10:28:22 2017 +0700

----------------------------------------------------------------------
 .../visor/cache/VisorCacheStopTask.java         | 22 ++++++++--------
 .../visor/cache/VisorCacheStopTaskArg.java      | 27 ++++++++++++++++++++
 2 files changed, 39 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/5c209785/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTask.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTask.java
index 9f7c018..df95c5e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTask.java
@@ -17,8 +17,10 @@
 
 package org.apache.ignite.internal.visor.cache;
 
-import org.apache.ignite.IgniteCache;
+import java.util.Collection;
+import java.util.HashSet;
 import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.visor.VisorJob;
 import org.apache.ignite.internal.visor.VisorOneNodeTask;
@@ -46,23 +48,23 @@ public class VisorCacheStopTask extends VisorOneNodeTask<VisorCacheStopTaskArg,
         /**
          * Create job.
          *
-         * @param cacheName Cache name to clear.
+         * @param arg Task argument.
          * @param debug Debug flag.
          */
-        private VisorCacheStopJob(VisorCacheStopTaskArg cacheName, boolean debug) {
-            super(cacheName, debug);
+        private VisorCacheStopJob(VisorCacheStopTaskArg arg, boolean debug) {
+            super(arg, debug);
         }
 
         /** {@inheritDoc} */
         @Override protected Void run(VisorCacheStopTaskArg arg) {
-            String cacheName = arg.getCacheName();
+            Collection<String> cacheNames = F.isEmpty(arg.getCacheNames())
+                ? F.asList(arg.getCacheName())
+                : new HashSet<>(arg.getCacheNames());
 
-            IgniteCache cache = ignite.cache(cacheName);
+            if (F.isEmpty(cacheNames))
+                throw new IllegalStateException("Cache names was not specified.");
 
-            if (cache == null)
-                throw new IllegalStateException("Failed to find cache for name: " + cacheName);
-
-            cache.destroy();
+            ignite.destroyCaches(cacheNames);
 
             return null;
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/5c209785/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTaskArg.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTaskArg.java
index 4976036..77156ab 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTaskArg.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheStopTaskArg.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.visor.cache;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.util.List;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.internal.visor.VisorDataTransferObject;
@@ -34,6 +35,9 @@ public class VisorCacheStopTaskArg extends VisorDataTransferObject {
     /** Cache name. */
     private String cacheName;
 
+    /** Cache names. */
+    private List<String> cacheNames;
+
     /**
      * Default constructor.
      */
@@ -49,20 +53,43 @@ public class VisorCacheStopTaskArg extends VisorDataTransferObject {
     }
 
     /**
+     * @param cacheNames Cache names.
+     */
+    public VisorCacheStopTaskArg(List<String> cacheNames) {
+        this.cacheNames = cacheNames;
+    }
+
+    /**
      * @return Cache name.
      */
     public String getCacheName() {
         return cacheName;
     }
 
+    /**
+     * @return Cache names.
+     */
+    public List<String> getCacheNames() {
+        return cacheNames;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte getProtocolVersion() {
+        return V2;
+    }
+
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
         U.writeString(out, cacheName);
+        U.writeCollection(out, cacheNames);
     }
 
     /** {@inheritDoc} */
     @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
         cacheName = U.readString(in);
+
+        if (protoVer > V1)
+            cacheNames = U.readList(in);
     }
 
     /** {@inheritDoc} */


[27/29] ignite git commit: IGNITE-5995: ODBC fix for SQLGetData.

Posted by nt...@apache.org.
IGNITE-5995: ODBC fix for SQLGetData.

(cherry picked from commit 0d8d166)


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

Branch: refs/heads/ignite-5947
Commit: 276e84a91bcea9c6b076ff674cdd16d93fbbde4d
Parents: 621380d
Author: Igor Sapego <is...@gridgain.com>
Authored: Thu Aug 10 15:31:44 2017 +0300
Committer: Igor Sapego <is...@gridgain.com>
Committed: Tue Aug 15 16:53:57 2017 +0300

----------------------------------------------------------------------
 .../impl/cache/query/query_fields_row_impl.h    |   2 +-
 .../cpp/odbc-test/include/test_utils.h          |   9 ++
 .../cpp/odbc-test/src/meta_queries_test.cpp     | 100 +++++++++++++++++++
 .../platforms/cpp/odbc-test/src/test_utils.cpp  |  13 +++
 .../ignite/odbc/query/column_metadata_query.h   |   3 +
 .../ignite/odbc/query/table_metadata_query.h    |   3 +
 .../include/ignite/odbc/query/type_info_query.h |   3 +
 .../cpp/odbc/src/query/batch_query.cpp          |   7 +-
 .../odbc/src/query/column_metadata_query.cpp    |  16 ++-
 .../platforms/cpp/odbc/src/query/data_query.cpp |   7 +-
 .../cpp/odbc/src/query/table_metadata_query.cpp |  16 ++-
 .../cpp/odbc/src/query/type_info_query.cpp      |  16 ++-
 12 files changed, 183 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
index 63e0523..2943625 100644
--- a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
+++ b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h
@@ -143,7 +143,7 @@ namespace ignite
 
                             int32_t actualLen = reader.ReadInt8Array(dst, len);
 
-                            if (actualLen == 0 || dst && len >= actualLen)
+                            if (actualLen == 0 || (dst && len >= actualLen))
                                 ++processed;
 
                             return actualLen;

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc-test/include/test_utils.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/include/test_utils.h b/modules/platforms/cpp/odbc-test/include/test_utils.h
index 6a58e54..5dc6d6e 100644
--- a/modules/platforms/cpp/odbc-test/include/test_utils.h
+++ b/modules/platforms/cpp/odbc-test/include/test_utils.h
@@ -43,6 +43,15 @@ namespace ignite_test
     enum { ODBC_BUFFER_SIZE = 1024 };
 
     /**
+     * Extract error state.
+     *
+     * @param handleType Type of the handle.
+     * @param handle Handle.
+     * @return Error state.
+     */
+    std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle);
+
+    /**
      * Extract error message.
      *
      * @param handleType Type of the handle.

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
index 454a989..ff3695d 100644
--- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
@@ -103,6 +103,9 @@ struct MetaQueriesTestSuiteFixture
         BOOST_REQUIRE(stmt != NULL);
     }
 
+    /**
+     * Disconnect.
+     */
     void Disconnect()
     {
         // Releasing statement handle.
@@ -116,6 +119,11 @@ struct MetaQueriesTestSuiteFixture
         SQLFreeHandle(SQL_HANDLE_ENV, env);
     }
 
+    /**
+     * Start additional node with the specified name.
+     *
+     * @param name Node name.
+     */
     static Ignite StartAdditionalNode(const char* name)
     {
 #ifdef IGNITE_TESTS_32
@@ -126,6 +134,36 @@ struct MetaQueriesTestSuiteFixture
     }
 
     /**
+     * Checks single row result set for correct work with SQLGetData.
+     *
+     * @param stmt Statement.
+     */
+    void CheckSingleRowResultSetWithGetData(SQLHSTMT stmt)
+    {
+        SQLRETURN ret = SQLFetch(stmt);
+
+        if (!SQL_SUCCEEDED(ret))
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+        char buf[1024];
+        SQLLEN bufLen = sizeof(buf);
+
+        ret = SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &bufLen);
+
+        if (!SQL_SUCCEEDED(ret))
+            BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+        ret = SQLFetch(stmt);
+
+        BOOST_REQUIRE_EQUAL(ret, SQL_NO_DATA);
+
+        ret = SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &bufLen);
+
+        BOOST_REQUIRE_EQUAL(ret, SQL_ERROR);
+        BOOST_CHECK_EQUAL(GetOdbcErrorState(SQL_HANDLE_STMT, stmt), "24000");
+    }
+
+    /**
      * Constructor.
      */
     MetaQueriesTestSuiteFixture() :
@@ -237,4 +275,66 @@ BOOST_AUTO_TEST_CASE(TestColAttributesColumnScale)
         BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
 }
 
+BOOST_AUTO_TEST_CASE(TestGetDataWithGetTypeInfo)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLRETURN ret = SQLGetTypeInfo(stmt, SQL_VARCHAR);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    CheckSingleRowResultSetWithGetData(stmt);
+}
+
+BOOST_AUTO_TEST_CASE(TestGetDataWithTables)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLCHAR empty[] = "";
+    SQLCHAR table[] = "TestType";
+
+    SQLRETURN ret = SQLTables(stmt, empty, SQL_NTS, empty, SQL_NTS, table, SQL_NTS, empty, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    CheckSingleRowResultSetWithGetData(stmt);
+}
+
+BOOST_AUTO_TEST_CASE(TestGetDataWithColumns)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLCHAR empty[] = "";
+    SQLCHAR table[] = "TestType";
+    SQLCHAR column[] = "strField";
+
+    SQLRETURN ret = SQLColumns(stmt, empty, SQL_NTS, empty, SQL_NTS, table, SQL_NTS, column, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    CheckSingleRowResultSetWithGetData(stmt);
+}
+
+BOOST_AUTO_TEST_CASE(TestGetDataWithSelectQuery)
+{
+    Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+    SQLCHAR insertReq[] = "insert into TestType(_key, strField) VALUES(1, 'Lorem ipsum')";
+    SQLRETURN ret = SQLExecDirect(stmt, insertReq, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    SQLCHAR selectReq[] = "select strField from TestType";
+    ret = SQLExecDirect(stmt, selectReq, SQL_NTS);
+
+    if (!SQL_SUCCEEDED(ret))
+        BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+    CheckSingleRowResultSetWithGetData(stmt);
+}
+
 BOOST_AUTO_TEST_SUITE_END()

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc-test/src/test_utils.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/test_utils.cpp b/modules/platforms/cpp/odbc-test/src/test_utils.cpp
index c7aa70a..6e8fe6a 100644
--- a/modules/platforms/cpp/odbc-test/src/test_utils.cpp
+++ b/modules/platforms/cpp/odbc-test/src/test_utils.cpp
@@ -21,6 +21,19 @@
 
 namespace ignite_test
 {
+    std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle)
+    {
+        SQLCHAR sqlstate[7] = {};
+        SQLINTEGER nativeCode;
+
+        SQLCHAR message[ODBC_BUFFER_SIZE];
+        SQLSMALLINT reallen = 0;
+
+        SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen);
+
+        return std::string(reinterpret_cast<char*>(sqlstate));
+    }
+
     std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle)
     {
         SQLCHAR sqlstate[7] = {};

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h b/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h
index 878a4be..875b1ce 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h
@@ -130,6 +130,9 @@ namespace ignite
                 /** Query executed. */
                 bool executed;
 
+                /** Fetched flag. */
+                bool fetched;
+
                 /** Fetched metadata. */
                 meta::ColumnMetaVector meta;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h b/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h
index cef963c..acd3f49 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h
@@ -134,6 +134,9 @@ namespace ignite
                 /** Query executed. */
                 bool executed;
 
+                /** Fetched flag. */
+                bool fetched;
+
                 /** Fetched metadata. */
                 meta::TableMetaVector meta;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h b/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h
index a7cee92..00cca08 100644
--- a/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h
+++ b/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h
@@ -105,6 +105,9 @@ namespace ignite
                 /** Executed flag. */
                 bool executed;
 
+                /** Fetched flag. */
+                bool fetched;
+
                 /** Requested types. */
                 std::vector<int8_t> types;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/src/query/batch_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/batch_query.cpp b/modules/platforms/cpp/odbc/src/query/batch_query.cpp
index df9fb05..46447c0 100644
--- a/modules/platforms/cpp/odbc/src/query/batch_query.cpp
+++ b/modules/platforms/cpp/odbc/src/query/batch_query.cpp
@@ -112,7 +112,12 @@ namespace ignite
                 }
 
                 if (dataRetrieved)
-                    return SqlResult::AI_NO_DATA;
+                {
+                    diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE,
+                        "Cursor has reached end of the result set.");
+
+                    return SqlResult::AI_ERROR;
+                }
 
                 if (columnIdx != 1)
                 {

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
index 8ba9323..b9c08f5 100644
--- a/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
+++ b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp
@@ -83,6 +83,7 @@ namespace ignite
                 table(table),
                 column(column),
                 executed(false),
+                fetched(false),
                 meta(),
                 columnsMeta()
             {
@@ -125,6 +126,7 @@ namespace ignite
                 if (result == SqlResult::AI_SUCCESS)
                 {
                     executed = true;
+                    fetched = false;
 
                     cursor = meta.begin();
                 }
@@ -146,6 +148,11 @@ namespace ignite
                     return SqlResult::AI_ERROR;
                 }
 
+                if (!fetched)
+                    fetched = true;
+                else
+                    ++cursor;
+
                 if (cursor == meta.end())
                     return SqlResult::AI_NO_DATA;
 
@@ -154,8 +161,6 @@ namespace ignite
                 for (it = columnBindings.begin(); it != columnBindings.end(); ++it)
                     GetColumn(it->first, it->second);
 
-                ++cursor;
-
                 return SqlResult::AI_SUCCESS;
             }
 
@@ -169,7 +174,12 @@ namespace ignite
                 }
 
                 if (cursor == meta.end())
-                    return SqlResult::AI_NO_DATA;
+                {
+                    diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE,
+                        "Cursor has reached end of the result set.");
+
+                    return SqlResult::AI_ERROR;
+                }
 
                 const meta::ColumnMeta& currentColumn = *cursor;
                 uint8_t columnType = currentColumn.GetDataType();

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/src/query/data_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/data_query.cpp b/modules/platforms/cpp/odbc/src/query/data_query.cpp
index 23d5240..f14d004 100644
--- a/modules/platforms/cpp/odbc/src/query/data_query.cpp
+++ b/modules/platforms/cpp/odbc/src/query/data_query.cpp
@@ -125,7 +125,12 @@ namespace ignite
                 Row* row = cursor->GetRow();
 
                 if (!row)
-                    return SqlResult::AI_NO_DATA;
+                {
+                    diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE,
+                        "Cursor has reached end of the result set.");
+
+                    return SqlResult::AI_ERROR;
+                }
 
                 SqlResult::Type result = row->ReadColumnToBuffer(columnIdx, buffer);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp b/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp
index 401a1d2..e66b281 100644
--- a/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp
+++ b/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp
@@ -63,6 +63,7 @@ namespace ignite
                 table(table),
                 tableType(tableType),
                 executed(false),
+                fetched(false),
                 meta(),
                 columnsMeta()
             {
@@ -98,6 +99,7 @@ namespace ignite
                 if (result == SqlResult::AI_SUCCESS)
                 {
                     executed = true;
+                    fetched = false;
 
                     cursor = meta.begin();
                 }
@@ -119,6 +121,11 @@ namespace ignite
                     return SqlResult::AI_ERROR;
                 }
 
+                if (!fetched)
+                    fetched = true;
+                else
+                    ++cursor;
+
                 if (cursor == meta.end())
                     return SqlResult::AI_NO_DATA;
 
@@ -127,8 +134,6 @@ namespace ignite
                 for (it = columnBindings.begin(); it != columnBindings.end(); ++it)
                     GetColumn(it->first, it->second);
 
-                ++cursor;
-
                 return SqlResult::AI_SUCCESS;
             }
 
@@ -142,7 +147,12 @@ namespace ignite
                 }
 
                 if (cursor == meta.end())
-                    return SqlResult::AI_NO_DATA;
+                {
+                    diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE,
+                        "Cursor has reached end of the result set.");
+
+                    return SqlResult::AI_ERROR;
+                }
 
                 const meta::TableMeta& currentColumn = *cursor;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/276e84a9/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc/src/query/type_info_query.cpp b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
index f6b3990..b4efca0 100644
--- a/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
+++ b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp
@@ -122,6 +122,7 @@ namespace ignite
                 Query(diag, QueryType::TYPE_INFO),
                 columnsMeta(),
                 executed(false),
+                fetched(false),
                 types(),
                 cursor(types.end())
             {
@@ -185,6 +186,7 @@ namespace ignite
                 cursor = types.begin();
 
                 executed = true;
+                fetched = false;
 
                 return SqlResult::AI_SUCCESS;
             }
@@ -203,6 +205,11 @@ namespace ignite
                     return SqlResult::AI_ERROR;
                 }
 
+                if (!fetched)
+                    fetched = true;
+                else
+                    ++cursor;
+
                 if (cursor == types.end())
                     return SqlResult::AI_NO_DATA;
 
@@ -211,8 +218,6 @@ namespace ignite
                 for (it = columnBindings.begin(); it != columnBindings.end(); ++it)
                     GetColumn(it->first, it->second);
 
-                ++cursor;
-
                 return SqlResult::AI_SUCCESS;
             }
 
@@ -228,7 +233,12 @@ namespace ignite
                 }
 
                 if (cursor == types.end())
-                    return SqlResult::AI_NO_DATA;
+                {
+                    diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE,
+                        "Cursor has reached end of the result set.");
+
+                    return SqlResult::AI_ERROR;
+                }
 
                 int8_t currentType = *cursor;