Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-545 cd9638373 -> 1652fd181


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/hibernate/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/hibernate/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java
 
b/modules/hibernate/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java
new file mode 100644
index 0000000..c30e216
--- /dev/null
+++ 
b/modules/hibernate/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.cache.store.hibernate;
+
+import org.apache.ignite.cache.store.*;
+import org.apache.ignite.cache.store.jdbc.*;
+import org.apache.ignite.lang.*;
+import org.apache.ignite.resources.*;
+import org.hibernate.*;
+import org.hibernate.cfg.Configuration;
+
+import javax.cache.Cache;
+import javax.cache.configuration.*;
+import javax.cache.integration.*;
+import javax.persistence.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Tests for {@link CacheJdbcStoreSessionListener}.
+ */
+public class CacheHibernateStoreSessionListenerSelfTest extends 
CacheStoreSessionListenerAbstractSelfTest {
+    /** {@inheritDoc} */
+    @Override protected Factory<? extends CacheStore<Integer, Integer>> 
storeFactory() {
+        return new Factory<CacheStore<Integer, Integer>>() {
+            @Override public CacheStore<Integer, Integer> create() {
+                return new Store();
+            }
+        };
+    }
+
+    /** {@inheritDoc} */
+    @Override protected Factory<CacheStoreSessionListener> 
sessionListenerFactory() {
+        return new Factory<CacheStoreSessionListener>() {
+            @Override public CacheStoreSessionListener create() {
+                CacheHibernateStoreSessionListener lsnr = new 
CacheHibernateStoreSessionListener();
+
+                SessionFactory sesFactory = new Configuration().
+                    setProperty("hibernate.connection.url", URL).
+                    addAnnotatedClass(Table1.class).
+                    addAnnotatedClass(Table2.class).
+                    buildSessionFactory();
+
+                lsnr.setSessionFactory(sesFactory);
+
+                return lsnr;
+            }
+        };
+    }
+
+    /**
+     */
+    private static class Store extends CacheStoreAdapter<Integer, Integer> {
+        /** */
+        private static String SES_CONN_KEY = "ses_conn";
+
+        /** */
+        @CacheStoreSessionResource
+        private CacheStoreSession ses;
+
+        /** {@inheritDoc} */
+        @Override public void loadCache(IgniteBiInClosure<Integer, Integer> 
clo, Object... args) {
+            loadCacheCnt.incrementAndGet();
+
+            checkSession();
+        }
+
+        /** {@inheritDoc} */
+        @Override public Integer load(Integer key) throws CacheLoaderException 
{
+            loadCnt.incrementAndGet();
+
+            checkSession();
+
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Cache.Entry<? extends Integer, ? extends 
Integer> entry)
+            throws CacheWriterException {
+            writeCnt.incrementAndGet();
+
+            checkSession();
+
+            if (write.get()) {
+                Session hibSes = ses.attachment();
+
+                switch (ses.cacheName()) {
+                    case "cache1":
+                        hibSes.save(new Table1(entry.getKey(), 
entry.getValue()));
+
+                        break;
+
+                    case "cache2":
+                        if (fail.get())
+                            throw new CacheWriterException("Expected 
failure.");
+
+                        hibSes.save(new Table2(entry.getKey(), 
entry.getValue()));
+
+                        break;
+
+                    default:
+                        throw new CacheWriterException("Wring cache: " + 
ses.cacheName());
+                }
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void delete(Object key) throws CacheWriterException {
+            deleteCnt.incrementAndGet();
+
+            checkSession();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void sessionEnd(boolean commit) {
+            assertNull(ses.attachment());
+        }
+
+        /**
+         */
+        private void checkSession() {
+            Session hibSes = ses.attachment();
+
+            assertNotNull(hibSes);
+
+            assertTrue(hibSes.isOpen());
+
+            Transaction tx = hibSes.getTransaction();
+
+            assertNotNull(tx);
+
+            if (ses.isWithinTransaction())
+                assertTrue(tx.isActive());
+            else
+                assertFalse(tx.isActive());
+
+            verifySameInstance(hibSes);
+        }
+
+        /**
+         * @param hibSes Session.
+         */
+        private void verifySameInstance(Session hibSes) {
+            Map<String, Session> props = ses.properties();
+
+            Session sesConn = props.get(SES_CONN_KEY);
+
+            if (sesConn == null)
+                props.put(SES_CONN_KEY, hibSes);
+            else {
+                assertSame(hibSes, sesConn);
+
+                reuseCnt.incrementAndGet();
+            }
+        }
+    }
+
+    /**
+     */
+    @Entity
+    @Table(name = "Table1")
+    private static class Table1 implements Serializable {
+        /** */
+        @Id @GeneratedValue
+        @Column(name = "id")
+        private Integer id;
+
+        /** */
+        @Column(name = "key")
+        private int key;
+
+        /** */
+        @Column(name = "value")
+        private int value;
+
+        /**
+         * @param key Key.
+         * @param value Value.
+         */
+        private Table1(int key, int value) {
+            this.key = key;
+            this.value = value;
+        }
+    }
+
+    /**
+     */
+    @Entity
+    @Table(name = "Table2")
+    private static class Table2 implements Serializable {
+        /** */
+        @Id @GeneratedValue
+        @Column(name = "id")
+        private Integer id;
+
+        /** */
+        @Column(name = "key")
+        private int key;
+
+        /** */
+        @Column(name = "value")
+        private int value;
+
+        /**
+         * @param key Key.
+         * @param value Value.
+         */
+        private Table2(int key, int value) {
+            this.key = key;
+            this.value = value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/hibernate/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/hibernate/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
 
b/modules/hibernate/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
index da741f8..655e801 100644
--- 
a/modules/hibernate/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
+++ 
b/modules/hibernate/src/test/java/org/apache/ignite/testsuites/IgniteHibernateTestSuite.java
@@ -41,6 +41,8 @@ public class IgniteHibernateTestSuite extends TestSuite {
 
         suite.addTestSuite(CacheHibernateBlobStoreNodeRestartTest.class);
 
+        suite.addTestSuite(CacheHibernateStoreSessionListenerSelfTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexEntryEvictTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexEntryEvictTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexEntryEvictTest.java
new file mode 100644
index 0000000..8afd746
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexEntryEvictTest.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.*;
+import org.apache.ignite.cache.query.*;
+import org.apache.ignite.configuration.*;
+import org.apache.ignite.spi.discovery.tcp.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*;
+import org.apache.ignite.spi.swapspace.file.*;
+import org.apache.ignite.testframework.junits.common.*;
+
+import javax.cache.*;
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.locks.*;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.*;
+import static org.apache.ignite.cache.CacheMemoryMode.*;
+import static org.apache.ignite.cache.CacheMode.*;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*;
+
+/**
+ *
+ */
+public class GridCacheOffheapIndexEntryEvictTest extends 
GridCommonAbstractTest {
+    /** */
+    private final TcpDiscoveryIpFinder ipFinder = new 
TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(ipFinder);
+
+        cfg.setDiscoverySpi(disco);
+
+        cfg.setNetworkTimeout(2000);
+
+        cfg.setSwapSpaceSpi(new FileSwapSpaceSpi());
+
+        CacheConfiguration cacheCfg = defaultCacheConfiguration();
+
+        cacheCfg.setWriteSynchronizationMode(FULL_SYNC);
+        cacheCfg.setCacheMode(PARTITIONED);
+        cacheCfg.setBackups(1);
+        cacheCfg.setOffHeapMaxMemory(0);
+        cacheCfg.setAtomicityMode(TRANSACTIONAL);
+        cacheCfg.setMemoryMode(OFFHEAP_TIERED);
+        cacheCfg.setEvictionPolicy(null);
+        cacheCfg.setSqlOnheapRowCacheSize(10);
+        cacheCfg.setIndexedTypes(Integer.class, TestValue.class);
+        cacheCfg.setNearConfiguration(null);
+
+        cfg.setCacheConfiguration(cacheCfg);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrids(1);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testQueryWhenLocked() throws Exception {
+        IgniteCache<Integer, TestValue> cache = grid(0).cache(null);
+
+        List<Lock> locks = new ArrayList<>();
+
+        final int ENTRIES = 1000;
+
+        try {
+            for (int i = 0; i < ENTRIES; i++) {
+                cache.put(i, new TestValue(i));
+
+                Lock lock = cache.lock(i);
+
+                lock.lock(); // Lock entry so that it should not be evicted.
+
+                locks.add(lock);
+
+                for (int j = 0; j < 3; j++)
+                    assertNotNull(cache.get(i));
+            }
+
+            checkQuery(cache, "_key >= 100", ENTRIES - 100);
+        }
+        finally {
+            for (Lock lock : locks)
+                lock.unlock();
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testUpdates() throws Exception {
+        final int ENTRIES = 500;
+
+        IgniteCache<Integer, TestValue> cache = grid(0).cache(null);
+
+        for (int i = 0; i < ENTRIES; i++) {
+            for (int j = 0; j < 3; j++) {
+                cache.getAndPut(i, new TestValue(i));
+
+                assertNotNull(cache.get(i));
+
+                assertNotNull(cache.localPeek(i));
+            }
+
+            checkQuery(cache, "_key >= 0", i + 1);
+        }
+
+        for (int i = 0; i < ENTRIES; i++) {
+            if (i % 2 == 0)
+                cache.getAndRemove(i);
+            else
+                cache.remove(i);
+
+            checkQuery(cache, "_key >= 0", ENTRIES - (i + 1));
+        }
+    }
+
+    /**
+     * @param cache Cache.
+     * @param sql Query.
+     * @param expCnt Number of expected entries.
+     */
+    private void checkQuery(IgniteCache<Integer, TestValue> cache, String sql, 
int expCnt) {
+        SqlQuery<Integer, TestValue> qry = new SqlQuery<>(TestValue.class, 
sql);
+
+        List<Cache.Entry<Integer, TestValue>> res = cache.query(qry).getAll();
+
+        assertEquals(expCnt, res.size());
+
+        for (Cache.Entry<Integer, TestValue> e : res) {
+            assertNotNull(e.getKey());
+
+            assertEquals((int)e.getKey(), e.getValue().val);
+        }
+    }
+
+    /**
+     *
+     */
+    static class TestValue implements Externalizable {
+        /** */
+        private int val;
+
+        /**
+         *
+         */
+        public TestValue() {
+            // No-op.
+        }
+
+        /**
+         * @param val Value.
+         */
+        public TestValue(int val) {
+            this.val = val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeExternal(ObjectOutput out) throws 
IOException {
+            out.writeInt(val);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+            val = in.readInt();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexGetSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexGetSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexGetSelfTest.java
index 4e40040..4e613ae 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexGetSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheOffheapIndexGetSelfTest.java
@@ -18,12 +18,19 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.*;
+import org.apache.ignite.cache.query.*;
+import org.apache.ignite.cache.query.annotations.*;
 import org.apache.ignite.configuration.*;
 import org.apache.ignite.spi.discovery.tcp.*;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
 import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*;
 import org.apache.ignite.spi.swapspace.file.*;
 import org.apache.ignite.testframework.junits.common.*;
+import org.apache.ignite.transactions.*;
+
+import javax.cache.*;
+import java.io.*;
+import java.util.*;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.*;
 import static org.apache.ignite.cache.CacheMemoryMode.*;
@@ -67,8 +74,7 @@ public class GridCacheOffheapIndexGetSelfTest extends 
GridCommonAbstractTest {
         cacheCfg.setAtomicityMode(TRANSACTIONAL);
         cacheCfg.setMemoryMode(OFFHEAP_TIERED);
         cacheCfg.setEvictionPolicy(null);
-        cacheCfg.setOffHeapMaxMemory(OFFHEAP_MEM);
-        cacheCfg.setIndexedTypes(Long.class, Long.class);
+        cacheCfg.setIndexedTypes(Long.class, Long.class, String.class, 
TestEntity.class);
 
         cfg.setCacheConfiguration(cacheCfg);
 
@@ -98,8 +104,6 @@ public class GridCacheOffheapIndexGetSelfTest extends 
GridCommonAbstractTest {
      * @throws Exception If failed.
      */
     public void testGet() throws Exception {
-        fail("https://issues.apache.org/jira/browse/IGNITE-873";);
-
         IgniteCache<Long, Long> cache = grid(0).cache(null);
 
         for (long i = 0; i < 100; i++)
@@ -107,5 +111,73 @@ public class GridCacheOffheapIndexGetSelfTest extends 
GridCommonAbstractTest {
 
         for (long i = 0; i < 100; i++)
             assertEquals((Long)i, cache.get(i));
+
+        SqlQuery<Long, Long> qry = new SqlQuery<>(Long.class, "_val >= 90");
+
+        List<Cache.Entry<Long, Long>> res = cache.query(qry).getAll();
+
+        assertEquals(10, res.size());
+
+        for (Cache.Entry<Long, Long> e : res) {
+            assertNotNull(e.getKey());
+            assertNotNull(e.getValue());
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPutGet() throws Exception {
+        IgniteCache<Object, Object> cache = grid(0).cache(null);
+
+        Map map = new HashMap();
+
+        try (Transaction tx = 
grid(0).transactions().txStart(TransactionConcurrency.PESSIMISTIC,
+            TransactionIsolation.REPEATABLE_READ, 100000, 1000)) {
+
+            for (int i = 4; i < 400; i++) {
+                map.put("key" + i, new TestEntity("value"));
+                map.put(i, "value");
+            }
+
+            cache.putAll(map);
+
+            tx.commit();
+        }
+
+        for (int i = 0; i < 100; i++) {
+            cache.get("key" + i);
+            cache.get(i);
+        }
+    }
+
+    /**
+     * Test entry class.
+     */
+    private static class TestEntity implements Serializable {
+        /** Value. */
+        @QuerySqlField(index = true)
+        private String val;
+
+        /**
+         * @param value Value.
+         */
+        public TestEntity(String value) {
+            this.val = value;
+        }
+
+        /**
+         * @return Value.
+         */
+        public String getValue() {
+            return val;
+        }
+
+        /**
+         * @param val Value
+         */
+        public void setValue(String val) {
+            this.val = val;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQueryMetricsSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQueryMetricsSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQueryMetricsSelfTest.java
index 81c2820..24011b4 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQueryMetricsSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheQueryMetricsSelfTest.java
@@ -62,26 +62,35 @@ public class GridCacheQueryMetricsSelfTest extends 
GridCommonAbstractTest {
 
         cfg.setDiscoverySpi(disco);
 
-        CacheConfiguration cacheCfg = defaultCacheConfiguration();
+        CacheConfiguration<String, Integer> cacheCfg1 = 
defaultCacheConfiguration();
 
-        cacheCfg.setCacheMode(CACHE_MODE);
-        cacheCfg.setWriteSynchronizationMode(FULL_SYNC);
-        cacheCfg.setIndexedTypes(String.class, Integer.class);
+        cacheCfg1.setName("A");
+        cacheCfg1.setCacheMode(CACHE_MODE);
+        cacheCfg1.setWriteSynchronizationMode(FULL_SYNC);
+        cacheCfg1.setIndexedTypes(String.class, Integer.class);
 
-        cfg.setCacheConfiguration(cacheCfg);
+        CacheConfiguration<String, Integer> cacheCfg2 = 
defaultCacheConfiguration();
+
+        cacheCfg2.setName("B");
+        cacheCfg2.setCacheMode(CACHE_MODE);
+        cacheCfg2.setWriteSynchronizationMode(FULL_SYNC);
+        cacheCfg2.setIndexedTypes(String.class, Integer.class);
+
+        cfg.setCacheConfiguration(cacheCfg1, cacheCfg2);
 
         return cfg;
     }
 
     /**
-     * JUnit.
+     * Test metrics for SQL queries.
      *
      * @throws Exception In case of error.
      */
-    public void testAccumulativeMetrics() throws Exception {
-        IgniteCache<String, Integer> cache = grid(0).cache(null);
+    public void testSqlFieldsQueryMetrics() throws Exception {
+        IgniteCache<String, Integer> cache = 
grid(0).context().cache().jcache("A");
 
-        SqlQuery<String, Integer> qry = new SqlQuery(Integer.class, "_val >= 
0");
+        // Execute query.
+        SqlFieldsQuery qry = new SqlFieldsQuery("select * from Integer");
 
         cache.query(qry).getAll();
 
@@ -114,20 +123,22 @@ public class GridCacheQueryMetricsSelfTest extends 
GridCommonAbstractTest {
     }
 
     /**
-     * JUnit.
+     * Test metrics for Scan queries.
      *
      * @throws Exception In case of error.
      */
-    public void testSingleQueryMetrics() throws Exception {
-        IgniteCache<String, Integer> cache = grid(0).cache(null);
+    public void testScanQueryMetrics() throws Exception {
+        IgniteCache<String, Integer> cache = 
grid(0).context().cache().jcache("A");
 
-        SqlQuery<String, Integer> qry = new SqlQuery(Integer.class, "_val >= 
0");
+        // Execute query.
+        ScanQuery<String, Integer> qry = new ScanQuery<>();
 
-        // Execute.
         cache.query(qry).getAll();
 
         QueryMetrics m = cache.queryMetrics();
 
+        assert m != null;
+
         info("Metrics: " + m);
 
         assertEquals(1, m.executions());
@@ -136,11 +147,54 @@ public class GridCacheQueryMetricsSelfTest extends 
GridCommonAbstractTest {
         assertTrue(m.maximumTime() >= 0);
         assertTrue(m.minimumTime() >= 0);
 
-        // Execute.
+        // Execute again with the same parameters.
         cache.query(qry).getAll();
 
         m = cache.queryMetrics();
 
+        assert m != null;
+
+        info("Metrics: " + m);
+
+        assertEquals(2, m.executions());
+        assertEquals(0, m.fails());
+        assertTrue(m.averageTime() >= 0);
+        assertTrue(m.maximumTime() >= 0);
+        assertTrue(m.minimumTime() >= 0);
+    }
+
+    /**
+     * Test metrics for SQL cross cache queries.
+     *
+     * @throws Exception In case of error.
+     */
+    public void testSqlCrossCacheQueryMetrics() throws Exception {
+        IgniteCache<String, Integer> cache = 
grid(0).context().cache().jcache("A");
+
+        // Execute query.
+        SqlFieldsQuery qry = new SqlFieldsQuery("select * from \"B\".Integer");
+
+        cache.query(qry).getAll();
+
+        QueryMetrics m = cache.queryMetrics();
+
+        assert m != null;
+
+        info("Metrics: " + m);
+
+        assertEquals(1, m.executions());
+        assertEquals(0, m.fails());
+        assertTrue(m.averageTime() >= 0);
+        assertTrue(m.maximumTime() >= 0);
+        assertTrue(m.minimumTime() >= 0);
+
+        // Execute again with the same parameters.
+        cache.query(qry).getAll();
+
+        m = cache.queryMetrics();
+
+        assert m != null;
+
         info("Metrics: " + m);
 
         assertEquals(2, m.executions());

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridIndexingWithNoopSwapSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridIndexingWithNoopSwapSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridIndexingWithNoopSwapSelfTest.java
index 2c0962b..5b623da 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridIndexingWithNoopSwapSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/GridIndexingWithNoopSwapSelfTest.java
@@ -64,7 +64,11 @@ public class GridIndexingWithNoopSwapSelfTest extends 
GridCommonAbstractTest {
         cc.setRebalanceMode(SYNC);
         cc.setSwapEnabled(true);
         cc.setNearConfiguration(new NearCacheConfiguration());
-        cc.setEvictionPolicy(new FifoEvictionPolicy(1000));
+
+        FifoEvictionPolicy plc = new FifoEvictionPolicy();
+        plc.setMaxSize(1000);
+
+        cc.setEvictionPolicy(plc);
         cc.setBackups(1);
         cc.setAtomicityMode(TRANSACTIONAL);
         cc.setIndexedTypes(

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
index 1a60bbd..6224cb9 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractQuerySelfTest.java
@@ -99,11 +99,7 @@ public abstract class IgniteCacheAbstractQuerySelfTest 
extends GridCommonAbstrac
     @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
         IgniteConfiguration c = super.getConfiguration(gridName);
 
-        TcpDiscoverySpi disco = new TcpDiscoverySpi();
-
-        disco.setIpFinder(ipFinder);
-
-        c.setDiscoverySpi(disco);
+        c.setDiscoverySpi(new 
TcpDiscoverySpi().setForceServerMode(true).setIpFinder(ipFinder));
 
         // Otherwise noop swap space will be chosen on Windows.
         c.setSwapSpaceSpi(new FileSwapSpaceSpi());

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheConfigurationPrimitiveTypesSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheConfigurationPrimitiveTypesSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheConfigurationPrimitiveTypesSelfTest.java
new file mode 100644
index 0000000..e90f10c
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheConfigurationPrimitiveTypesSelfTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.*;
+import org.apache.ignite.cache.query.*;
+import org.apache.ignite.configuration.*;
+import org.apache.ignite.spi.discovery.tcp.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*;
+import org.apache.ignite.testframework.junits.common.*;
+
+/**
+ *
+ */
+@SuppressWarnings("unchecked")
+public class IgniteCacheConfigurationPrimitiveTypesSelfTest extends 
GridCommonAbstractTest {
+    /** */
+    private static TcpDiscoveryIpFinder ipFinder = new 
TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(ipFinder);
+
+        cfg.setDiscoverySpi(disco);
+
+        return cfg;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testPrimitiveTypes() throws Exception {
+        Ignite ignite = startGrid(1);
+
+        CacheConfiguration<Object, Object> ccfg = new 
CacheConfiguration<>("c1");
+
+        ccfg.setIndexedTypes(
+            byte.class, byte.class,
+            short.class, short.class,
+            int.class, int.class,
+            long.class, long.class,
+            float.class, float.class,
+            double.class, double.class,
+            boolean.class, boolean.class);
+
+        IgniteCache<Object, Object> cache = ignite.getOrCreateCache(ccfg);
+
+        byte b = 1;
+        cache.put(b, b);
+
+        short s = 2;
+        cache.put(s, s);
+
+        int i = 3;
+        cache.put(i, i);
+
+        long l = 4;
+        cache.put(l, l);
+
+        float f = 5;
+        cache.put(f, f);
+
+        double d = 6;
+        cache.put(d, d);
+
+        boolean bool = true;
+        cache.put(bool, bool);
+
+        assert cache.query(new ScanQuery<>()).getAll().size() == 7;
+
+        assertEquals(cache.query(new SqlQuery<>(Byte.class, "1 = 
1")).getAll().size(), 1);
+        assertEquals(cache.query(new SqlQuery<>(Short.class, "1 = 
1")).getAll().size(), 1);
+        assertEquals(cache.query(new SqlQuery<>(Integer.class, "1 = 
1")).getAll().size(), 1);
+        assertEquals(cache.query(new SqlQuery<>(Long.class, "1 = 
1")).getAll().size(), 1);
+        assertEquals(cache.query(new SqlQuery<>(Float.class, "1 = 
1")).getAll().size(), 1);
+        assertEquals(cache.query(new SqlQuery<>(Double.class, "1 = 
1")).getAll().size(), 1);
+        assertEquals(cache.query(new SqlQuery<>(Boolean.class, "1 = 
1")).getAll().size(), 1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
index b2095a8..b171ead 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheP2pUnmarshallingQueryErrorTest.java
@@ -30,7 +30,8 @@ public class IgniteCacheP2pUnmarshallingQueryErrorTest 
extends IgniteCacheP2pUnm
     @Override protected IgniteConfiguration getConfiguration(String gridName) 
throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
-        cfg.getCacheConfiguration()[0].setIndexedTypes(TestKey.class, 
String.class);
+        if (cfg.getCacheConfiguration().length > 0)
+            cfg.getCacheConfiguration()[0].setIndexedTypes(TestKey.class, 
String.class);
 
         return cfg;
     }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedOffHeapTieredSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedOffHeapTieredSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedOffHeapTieredSelfTest.java
new file mode 100644
index 0000000..df4c01d
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedOffHeapTieredSelfTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.cache.*;
+import org.apache.ignite.configuration.*;
+
+/**
+ * Test queries in off-heap tiered mode.
+ */
+public class IgniteCacheQueryMultiThreadedOffHeapTieredSelfTest extends 
IgniteCacheQueryMultiThreadedSelfTest {
+    /** {@inheritDoc} */
+    @Override protected CacheConfiguration cacheConfiguration() {
+        CacheConfiguration ccfg = super.cacheConfiguration();
+
+        ccfg.setCacheMode(CacheMode.REPLICATED);
+        ccfg.setMemoryMode(CacheMemoryMode.OFFHEAP_TIERED);
+        ccfg.setOffHeapMaxMemory(0);
+
+        return ccfg;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedSelfTest.java
index 23a97c9..1d6bbc8 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheQueryMultiThreadedSelfTest.java
@@ -104,7 +104,16 @@ public class IgniteCacheQueryMultiThreadedSelfTest extends 
GridCommonAbstractTes
         
cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
         cacheCfg.setSwapEnabled(true);
         cacheCfg.setBackups(1);
-        cacheCfg.setEvictionPolicy(evictsEnabled() ? new 
LruEvictionPolicy(100) : null);
+
+        LruEvictionPolicy plc = null;
+
+        if (evictsEnabled()) {
+            plc = new LruEvictionPolicy();
+            plc.setMaxSize(100);
+        }
+
+        cacheCfg.setEvictionPolicy(plc);
+
         cacheCfg.setSqlOnheapRowCacheSize(128);
         cacheCfg.setIndexedTypes(
             Integer.class, Integer.class,

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ttl/CacheTtlAbstractSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ttl/CacheTtlAbstractSelfTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ttl/CacheTtlAbstractSelfTest.java
index 3833576..4553fec 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ttl/CacheTtlAbstractSelfTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ttl/CacheTtlAbstractSelfTest.java
@@ -67,7 +67,11 @@ public abstract class CacheTtlAbstractSelfTest extends 
GridCommonAbstractTest {
         ccfg.setAtomicityMode(atomicityMode());
         ccfg.setMemoryMode(memoryMode());
         ccfg.setOffHeapMaxMemory(0);
-        ccfg.setEvictionPolicy(new LruEvictionPolicy(MAX_CACHE_SIZE));
+
+        LruEvictionPolicy plc = new LruEvictionPolicy();
+        plc.setMaxSize(MAX_CACHE_SIZE);
+
+        ccfg.setEvictionPolicy(plc);
         ccfg.setIndexedTypes(Integer.class, Integer.class);
         ccfg.setBackups(2);
         ccfg.setWriteSynchronizationMode(FULL_SYNC);

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/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 f42963a..2d5fed5 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
@@ -59,10 +59,10 @@ public class IgniteCacheQuerySelfTestSuite extends 
TestSuite {
         suite.addTestSuite(IgniteCacheLargeResultSelfTest.class);
         suite.addTestSuite(GridCacheQueryInternalKeysSelfTest.class);
         suite.addTestSuite(IgniteCacheQueryMultiThreadedSelfTest.class);
-        
suite.addTestSuite(IgniteCacheQueryMultiThreadedOffHeapTiredSelfTest.class);
+        
suite.addTestSuite(IgniteCacheQueryMultiThreadedOffHeapTieredSelfTest.class);
         suite.addTestSuite(IgniteCacheQueryEvictsMultiThreadedSelfTest.class);
         suite.addTestSuite(IgniteCacheQueryOffheapMultiThreadedSelfTest.class);
-        
suite.addTestSuite(IgniteCacheQueryOffheapEvictsMultiThreadedSelfTest.class);
+        // 
suite.addTestSuite(IgniteCacheQueryOffheapEvictsMultiThreadedSelfTest.class); 
TODO IGNITE-971.
         suite.addTestSuite(IgniteCacheSqlQueryMultiThreadedSelfTest.class);
         
suite.addTestSuite(IgniteCacheOffheapTieredMultithreadedSelfTest.class);
 //        suite.addTestSuite(IgniteCacheQueryNodeRestartSelfTest.class); TODO 
IGNITE-484

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
index ae45120..67ebda9 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
@@ -47,9 +47,12 @@ public class IgniteCacheWithIndexingTestSuite extends 
TestSuite {
         suite.addTestSuite(CacheTtlOnheapAtomicPartitionedSelfTest.class);
 
         suite.addTestSuite(GridCacheOffheapIndexGetSelfTest.class);
+        suite.addTestSuite(GridCacheOffheapIndexEntryEvictTest.class);
 
         suite.addTestSuite(CacheConfigurationP2PTest.class);
 
+        
suite.addTestSuite(IgniteCacheConfigurationPrimitiveTypesSelfTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/mesos/pom.xml
----------------------------------------------------------------------
diff --git a/modules/mesos/pom.xml b/modules/mesos/pom.xml
index eca4fa9..c2bacff 100644
--- a/modules/mesos/pom.xml
+++ b/modules/mesos/pom.xml
@@ -23,7 +23,13 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>org.apache.ignite</groupId>
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-parent</artifactId>
+        <version>1</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
     <artifactId>ignite-mesos</artifactId>
     <version>1.1.1-SNAPSHOT</version>
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/spring/pom.xml
----------------------------------------------------------------------
diff --git a/modules/spring/pom.xml b/modules/spring/pom.xml
index e922215..a6e61ac 100644
--- a/modules/spring/pom.xml
+++ b/modules/spring/pom.xml
@@ -77,6 +77,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jdbc</artifactId>
+            <version>${spring.version}</version>
+        </dependency>
+
+        <dependency>
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
             <version>1.1.1</version>
@@ -103,6 +109,14 @@
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>
+
+
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.175</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListener.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListener.java
 
b/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListener.java
new file mode 100644
index 0000000..0a32816
--- /dev/null
+++ 
b/modules/spring/src/main/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListener.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.cache.store.spring;
+
+import org.apache.ignite.*;
+import org.apache.ignite.cache.store.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.lifecycle.*;
+import org.apache.ignite.resources.*;
+import org.apache.ignite.transactions.*;
+import org.springframework.jdbc.core.*;
+import org.springframework.jdbc.datasource.*;
+import org.springframework.transaction.*;
+import org.springframework.transaction.support.*;
+
+import javax.cache.integration.*;
+import javax.sql.*;
+
+/**
+ * Cache store session listener based on Spring transaction management.
+ * <p>
+ * This listener starts a new DB transaction for each session and commits
+ * or rolls it back when session ends. If there is no ongoing
+ * cache transaction, this listener is no-op.
+ * <p>
+ * Store implementation can use any Spring APIs like {@link JdbcTemplate}
+ * and others. The listener will guarantee that if there is an
+ * ongoing cache transaction, all store operations within this
+ * transaction will be automatically enlisted in the same database
+ * transaction.
+ * <p>
+ * {@link CacheSpringStoreSessionListener} requires that either
+ * {@link #setTransactionManager(PlatformTransactionManager) transaction 
manager}
+ * or {@link #setDataSource(DataSource) data source} is configured. If non of 
them is
+ * provided, exception is thrown. Is both are provided, data source will be
+ * ignored.
+ * <p>
+ * If there is a transaction, a {@link TransactionStatus} object will be saved
+ * as a store session {@link CacheStoreSession#attachment() attachment}. It
+ * can be used to acquire current DB transaction status.
+ */
+public class CacheSpringStoreSessionListener implements 
CacheStoreSessionListener, LifecycleAware {
+    /** Transaction manager. */
+    private PlatformTransactionManager txMgr;
+
+    /** Data source. */
+    private DataSource dataSrc;
+
+    /** Logger. */
+    @LoggerResource
+    private IgniteLogger log;
+
+    /**
+     * Sets transaction manager.
+     * <p>
+     * Either transaction manager or data source is required.
+     * If none is provided, exception will be thrown on startup.
+     *
+     * @param txMgr Transaction manager.
+     */
+    public void setTransactionManager(PlatformTransactionManager txMgr) {
+        this.txMgr = txMgr;
+    }
+
+    /**
+     * Gets transaction manager.
+     *
+     * @return Transaction manager.
+     */
+    public PlatformTransactionManager getTransactionManager() {
+        return txMgr;
+    }
+
+    /**
+     * Sets data source.
+     * <p>
+     * Either transaction manager or data source is required.
+     * If none is provided, exception will be thrown on startup.
+     *
+     * @param dataSrc Data source.
+     */
+    public void setDataSource(DataSource dataSrc) {
+        this.dataSrc = dataSrc;
+    }
+
+    /**
+     * Gets data source.
+     *
+     * @return Data source.
+     */
+    public DataSource getDataSource() {
+        return dataSrc;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start() throws IgniteException {
+        if (txMgr == null && dataSrc == null)
+            throw new IgniteException("Either transaction manager or data 
source is required by " +
+                getClass().getSimpleName() + '.');
+
+        if (dataSrc != null) {
+            if (txMgr == null)
+                txMgr = new DataSourceTransactionManager(dataSrc);
+            else
+                U.warn(log, "Data source configured in " + 
getClass().getSimpleName() +
+                    " will be ignored (transaction manager is already set).");
+        }
+
+        assert txMgr != null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() throws IgniteException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onSessionStart(CacheStoreSession ses) {
+        if (ses.isWithinTransaction() && ses.attachment() == null) {
+            try {
+                TransactionDefinition def = definition(ses.transaction(), 
ses.cacheName());
+
+                ses.attach(txMgr.getTransaction(def));
+            }
+            catch (TransactionException e) {
+                throw new CacheWriterException("Failed to start store session 
[tx=" + ses.transaction() + ']', e);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onSessionEnd(CacheStoreSession ses, boolean commit) {
+        if (ses.isWithinTransaction()) {
+            TransactionStatus tx = ses.attach(null);
+
+            if (tx != null) {
+                try {
+                    if (commit)
+                        txMgr.commit(tx);
+                    else
+                        txMgr.rollback(tx);
+                }
+                catch (TransactionException e) {
+                    throw new CacheWriterException("Failed to end store 
session [tx=" + ses.transaction() + ']', e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets DB transaction isolation level based on ongoing cache transaction 
isolation.
+     *
+     * @return DB transaction isolation.
+     */
+    private TransactionDefinition definition(Transaction tx, String cacheName) 
{
+        assert tx != null;
+
+        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
+
+        def.setName("Ignite Tx [cache=" + (cacheName != null ? cacheName : 
"<default>") + ", id=" + tx.xid() + ']');
+        def.setIsolationLevel(isolationLevel(tx.isolation()));
+
+        long timeoutSec = (tx.timeout() + 500) / 1000;
+
+        if (timeoutSec > 0 && timeoutSec < Integer.MAX_VALUE)
+            def.setTimeout((int)timeoutSec);
+
+        return def;
+    }
+
+    /**
+     * Gets DB transaction isolation level based on ongoing cache transaction 
isolation.
+     *
+     * @param isolation Cache transaction isolation.
+     * @return DB transaction isolation.
+     */
+    private int isolationLevel(TransactionIsolation isolation) {
+        switch (isolation) {
+            case READ_COMMITTED:
+                return TransactionDefinition.ISOLATION_READ_COMMITTED;
+
+            case REPEATABLE_READ:
+                return TransactionDefinition.ISOLATION_REPEATABLE_READ;
+
+            case SERIALIZABLE:
+                return TransactionDefinition.ISOLATION_SERIALIZABLE;
+
+            default:
+                throw new IllegalStateException(); // Will never happen.
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/spring/src/test/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListenerSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListenerSelfTest.java
 
b/modules/spring/src/test/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListenerSelfTest.java
new file mode 100644
index 0000000..74f5c69
--- /dev/null
+++ 
b/modules/spring/src/test/java/org/apache/ignite/cache/store/spring/CacheSpringStoreSessionListenerSelfTest.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.cache.store.spring;
+
+import org.apache.ignite.cache.store.*;
+import org.apache.ignite.cache.store.jdbc.*;
+import org.apache.ignite.lang.*;
+import org.apache.ignite.resources.*;
+import org.springframework.jdbc.core.*;
+import org.springframework.jdbc.datasource.*;
+import org.springframework.transaction.*;
+
+import javax.cache.*;
+import javax.cache.configuration.*;
+import javax.cache.integration.*;
+import javax.sql.*;
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Tests for {@link CacheJdbcStoreSessionListener}.
+ */
+public class CacheSpringStoreSessionListenerSelfTest extends 
CacheStoreSessionListenerAbstractSelfTest {
+    /** */
+    private static final DataSource DATA_SRC = new 
DriverManagerDataSource(URL);
+
+    /** {@inheritDoc} */
+    @Override protected Factory<? extends CacheStore<Integer, Integer>> 
storeFactory() {
+        return new Factory<CacheStore<Integer, Integer>>() {
+            @Override public CacheStore<Integer, Integer> create() {
+                return new Store(new JdbcTemplate(DATA_SRC));
+            }
+        };
+    }
+
+    /** {@inheritDoc} */
+    @Override protected Factory<CacheStoreSessionListener> 
sessionListenerFactory() {
+        return new Factory<CacheStoreSessionListener>() {
+            @Override public CacheStoreSessionListener create() {
+                CacheSpringStoreSessionListener lsnr = new 
CacheSpringStoreSessionListener();
+
+                lsnr.setDataSource(DATA_SRC);
+
+                return lsnr;
+            }
+        };
+    }
+
+    /**
+     */
+    private static class Store extends CacheStoreAdapter<Integer, Integer> {
+        /** */
+        private static String SES_CONN_KEY = "ses_conn";
+
+        /** */
+        private final JdbcTemplate jdbc;
+
+        /** */
+        @CacheStoreSessionResource
+        private CacheStoreSession ses;
+
+        /**
+         * @param jdbc JDBC template.
+         */
+        private Store(JdbcTemplate jdbc) {
+            this.jdbc = jdbc;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void loadCache(IgniteBiInClosure<Integer, Integer> 
clo, Object... args) {
+            loadCacheCnt.incrementAndGet();
+
+            checkTransaction();
+            checkConnection();
+        }
+
+        /** {@inheritDoc} */
+        @Override public Integer load(Integer key) throws CacheLoaderException 
{
+            loadCnt.incrementAndGet();
+
+            checkTransaction();
+            checkConnection();
+
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void write(Cache.Entry<? extends Integer, ? extends 
Integer> entry)
+            throws CacheWriterException {
+            writeCnt.incrementAndGet();
+
+            checkTransaction();
+            checkConnection();
+
+            if (write.get()) {
+                String table;
+
+                switch (ses.cacheName()) {
+                    case "cache1":
+                        table = "Table1";
+
+                        break;
+
+                    case "cache2":
+                        if (fail.get())
+                            throw new CacheWriterException("Expected 
failure.");
+
+                        table = "Table2";
+
+                        break;
+
+                    default:
+                        throw new CacheWriterException("Wring cache: " + 
ses.cacheName());
+                }
+
+                jdbc.update("INSERT INTO " + table + " (key, value) VALUES (?, 
?)",
+                    entry.getKey(), entry.getValue());
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void delete(Object key) throws CacheWriterException {
+            deleteCnt.incrementAndGet();
+
+            checkTransaction();
+            checkConnection();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void sessionEnd(boolean commit) {
+            assertNull(ses.attachment());
+        }
+
+        /**
+         */
+        private void checkTransaction() {
+            TransactionStatus tx = ses.attachment();
+
+            if (ses.isWithinTransaction()) {
+                assertNotNull(tx);
+                assertFalse(tx.isCompleted());
+            }
+            else
+                assertNull(tx);
+        }
+
+        /**
+         */
+        private void checkConnection() {
+            Connection conn = 
DataSourceUtils.getConnection(jdbc.getDataSource());
+
+            assertNotNull(conn);
+
+            try {
+                assertFalse(conn.isClosed());
+                assertEquals(!ses.isWithinTransaction(), conn.getAutoCommit());
+            }
+            catch (SQLException e) {
+                throw new RuntimeException(e);
+            }
+
+            verifySameInstance(conn);
+        }
+
+        /**
+         * @param conn Connection.
+         */
+        private void verifySameInstance(Connection conn) {
+            Map<String, Connection> props = ses.properties();
+
+            Connection sesConn = props.get(SES_CONN_KEY);
+
+            if (sesConn == null)
+                props.put(SES_CONN_KEY, conn);
+            else {
+                assertSame(conn, sesConn);
+
+                reuseCnt.incrementAndGet();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
 
b/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
index 8251c18..12dd494 100644
--- 
a/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
+++ 
b/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.testsuites;
 
 import junit.framework.*;
+import org.apache.ignite.cache.store.spring.*;
 import org.apache.ignite.internal.*;
 import org.apache.ignite.p2p.*;
 import org.apache.ignite.spring.*;
@@ -47,6 +48,8 @@ public class IgniteSpringTestSuite extends TestSuite {
 
         suite.addTest(new 
TestSuite(IgniteStartFromStreamConfigurationTest.class));
 
+        suite.addTestSuite(CacheSpringStoreSessionListenerSelfTest.class);
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala
 
b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala
index 4b66720..3aa2a19 100644
--- 
a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala
+++ 
b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala
@@ -139,7 +139,7 @@ class VisorCacheScanCommand {
         val firstPage =
             try
                 executeRandom(groupForDataNode(node, cacheName),
-                    classOf[VisorQueryTask], new VisorQueryArg(cacheName, 
"SCAN", false, pageSize)) match {
+                    classOf[VisorQueryTask], new VisorQueryArg(cacheName, 
null, false, pageSize)) match {
                     case x if x.get1() != null =>
                         error(x.get1())
 

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/scripts/git-apply-patch.sh
----------------------------------------------------------------------
diff --git a/scripts/git-apply-patch.sh b/scripts/git-apply-patch.sh
index c5f686f..757cd26 100755
--- a/scripts/git-apply-patch.sh
+++ b/scripts/git-apply-patch.sh
@@ -56,18 +56,18 @@ do
         IGNITE_HOME="$2"
         shift
         ;;
-        
+
         -idb|--ignitedefbranch)
         IGNITE_DEFAULT_BRANCH="$2"
         shift
         ;;
-        
+
         -ph|--patchhome)
         PATCHES_HOME="$2"
         shift
         ;;
         *)
-        
+
         echo "Unknown parameter: ${key}"
         ;;
     esac
@@ -75,7 +75,7 @@ do
 done
 
 echo "IGNITE_HOME    : ${IGNITE_HOME}"
-echo "Master branch  : ${IGNITE_DEFAULT_BRANCH}"
+echo "Default branch : ${IGNITE_DEFAULT_BRANCH}"
 echo "Ignite task    : ${IGNITE_TASK}"
 echo
 echo "PATCHES_HOME   : ${PATCHES_HOME}"

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/scripts/git-format-patch.sh
----------------------------------------------------------------------
diff --git a/scripts/git-format-patch.sh b/scripts/git-format-patch.sh
index 970347f..b11c73d 100755
--- a/scripts/git-format-patch.sh
+++ b/scripts/git-format-patch.sh
@@ -20,9 +20,13 @@
 # Git patch-file maker.
 #
 echo 'Usage: scripts/git-format-patch.sh [-ih|--ignitehome <path>] 
[-idb|--ignitedefbranch <branch-name>] [-ph|--patchhome <path>]'
+echo 'It is a script to create patch between Current branch (branch with 
changes) and Default branche. The script is safe and do not broke or lose your 
changes.'
 echo "It should be called from IGNITE_HOME directory."
-echo "Patch will be created at PATCHES_HOME between Master branch 
(IGNITE_DEFAULT_BRANCH) and Current branch."
+echo "Patch will be created at PATCHES_HOME (= IGNITE_HOME, by default) 
between Default branch (IGNITE_DEFAULT_BRANCH) and Current branch."
 echo "Note: you can use ${IGNITE_HOME}/scripts/git-patch-prop-local.sh to set 
your own local properties (to rewrite settings at git-patch-prop-local.sh). "
+echo 'Examples:'
+echo '- Basic (with all defaults and properties from git-patch-prop.sh):  
./scripts/git-format-patch.sh'
+echo '- Rewrite some defaults (see Usage):                                
./scripts/git-format-patch.sh -ph /home/user_name/patches'
 echo
 
 #
@@ -51,17 +55,17 @@ do
         IGNITE_HOME="$2"
         shift
         ;;
-        
+
         -idb|--ignitedefbranch)
         IGNITE_DEFAULT_BRANCH="$2"
         shift
         ;;
-        
+
         -ph|--patchhome)
         PATCHES_HOME="$2"
         shift
         ;;
-        
+
         *)
         echo "Unknown parameter: ${key}"
         ;;
@@ -72,7 +76,7 @@ done
 IGNITE_CURRENT_BRANCH=$( determineCurrentBranch ${IGNITE_HOME} )
 
 echo "IGNITE_HOME    : ${IGNITE_HOME}"
-echo "Master branch  : ${IGNITE_DEFAULT_BRANCH}"
+echo "Default branch : ${IGNITE_DEFAULT_BRANCH}"
 echo "Current branch : ${IGNITE_CURRENT_BRANCH}"
 echo
 echo "PATCHES_HOME   : ${PATCHES_HOME}"
@@ -84,4 +88,4 @@ echo
 
 requireCleanWorkTree ${IGNITE_HOME}
 
-formatPatch ${IGNITE_HOME} ${IGNITE_DEFAULT_BRANCH} ${IGNITE_CURRENT_BRANCH} 
.patch
\ No newline at end of file
+formatPatch ${IGNITE_HOME} ${IGNITE_DEFAULT_BRANCH} ${IGNITE_CURRENT_BRANCH} 
.patch

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1652fd18/scripts/git-patch-functions.sh
----------------------------------------------------------------------
diff --git a/scripts/git-patch-functions.sh b/scripts/git-patch-functions.sh
index 796bccd..3cc1bb0 100644
--- a/scripts/git-patch-functions.sh
+++ b/scripts/git-patch-functions.sh
@@ -39,6 +39,14 @@ formatPatch () {
     PATCHED_BRANCH=$3
     PATCH_SUFFIX=$4
 
+    if [ ${IGNITE_CURRENT_BRANCH} = ${IGNITE_DEFAULT_BRANCH} ]
+    then
+        echo $0", ERROR:"
+        echo "You are on Default branch. Please, checkout branch with changes."
+
+        exit 1
+    fi
+
     cd ${GIT_HOME}
 
     git checkout ${DEFAULT_BRANCH}
@@ -54,15 +62,15 @@ formatPatch () {
     echo "Patch file created."
 
     git checkout ${PATCHED_BRANCH}
-    
+
     git branch -D tmppatch # Delete tmp branch.
-    
-    echo 
+
+    echo
     echo "Patch created: ${PATCH_FILE}"
 }
 
 #
-# Determines current branch.
+# Determines Current branch.
 #
 # Params:
 # - Git home.
@@ -70,11 +78,11 @@ formatPatch () {
 #
 determineCurrentBranch () {
     GIT_HOME=$1
-    
+
     cd ${GIT_HOME}
-    
+
     CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD`
-    
+
     echo "$CURRENT_BRANCH"
 }
 
@@ -131,22 +139,22 @@ applyPatch () {
     PATCH_FILE=$3
 
     cd ${GIT_HOME}
-    
+
     if [ ! -f ${PATCH_FILE} ]
     then
         echo $0", ERROR:"
         echo "Expected patch file not found: $PATCH_FILE."
-        
+
         exit 1
     fi
 
     echo "Patch $PATCH_FILE will be applied to $DEFAULT_BRANCH branch."
-    
+
     git am ${PATCH_FILE}
 }
 
 #
-# Checks that given default branch and current branch are equal.
+# Checks that given Default branch and Current branch are equal.
 # Exit with code 1 in error case.
 #
 # Params:
@@ -160,12 +168,12 @@ currentAndDefaultBranchesShouldBeEqual () {
     cd ${GIT_HOME}
 
     CURRENT_BRANCH=$( determineCurrentBranch ${GIT_HOME} )
-    
+
     if [ "$CURRENT_BRANCH" != "$DEFAULT_BRANCH" ]
-    then 
+    then
         echo $0", ERROR:"
         echo "You are not on an expected branch. Your current branch at 
$GIT_HOME is $CURRENT_BRANCH, should be $DEFAULT_BRANCH."
-        
+
         exit 1
     fi
 }

Reply via email to