Fixed cache store examples
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/e1b2cf28 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/e1b2cf28 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/e1b2cf28 Branch: refs/heads/ignite-1537 Commit: e1b2cf2840b1451dbfc0bbef4540e5a9edaf6c35 Parents: 889b268 Author: Valentin Kulichenko <valentin.kuliche...@gmail.com> Authored: Thu Dec 17 16:05:09 2015 -0800 Committer: Valentin Kulichenko <valentin.kuliche...@gmail.com> Committed: Thu Dec 17 16:05:09 2015 -0800 ---------------------------------------------------------------------- .../hibernate/CacheHibernateStoreExample.java | 8 + .../datagrid/store/hibernate/Person.hbm.xml | 6 +- .../datagrid/store/hibernate/hibernate.cfg.xml | 7 +- .../store/spring/CacheSpringPersonStore.java | 118 ++++++++++++++ .../store/spring/CacheSpringStoreExample.java | 155 +++++++++++++++++++ .../datagrid/store/spring/package-info.java | 22 +++ 6 files changed, 311 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/e1b2cf28/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java index 71c4f68..db34eaf 100644 --- a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java +++ b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/CacheHibernateStoreExample.java @@ -30,6 +30,7 @@ import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.examples.ExampleNodeStartup; import org.apache.ignite.examples.ExamplesUtils; import org.apache.ignite.examples.model.Person; +import org.apache.ignite.examples.util.DbH2ServerStartup; import org.apache.ignite.transactions.Transaction; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; @@ -39,6 +40,13 @@ import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; * <p> * This example uses {@link CacheHibernatePersonStore} as a persistent store. * <p> + * To start the example, you should: + * <ul> + * <li>Start H2 database TCP server using {@link DbH2ServerStartup}.</li> + * <li>Start a few nodes using {@link ExampleNodeStartup}.</li> + * <li>Start example using {@link CacheHibernateStoreExample}.</li> + * </ul> + * <p> * Remote nodes can be started with {@link ExampleNodeStartup} in another JVM which will * start node with {@code examples/config/example-ignite.xml} configuration. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/e1b2cf28/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml ---------------------------------------------------------------------- diff --git a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml index 1314b71..0728a03 100644 --- a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml +++ b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml @@ -23,12 +23,12 @@ "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-access="field"> - <class name="org.apache.ignite.examples.model.Person" table="PERSONS"> + <class name="org.apache.ignite.examples.model.Person" table="PERSON"> <!-- ID. --> <id name="id"/> <!-- We only map data we are interested in. --> - <property name="firstName"/> - <property name="lastName"/> + <property name="firstName" column="first_name"/> + <property name="lastName" column="last_name"/> </class> </hibernate-mapping> http://git-wip-us.apache.org/repos/asf/ignite/blob/e1b2cf28/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/hibernate.cfg.xml ---------------------------------------------------------------------- diff --git a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/hibernate.cfg.xml b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/hibernate.cfg.xml index 80a43e7..7bf70af 100644 --- a/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/hibernate.cfg.xml +++ b/examples/src/main/java-lgpl/org/apache/ignite/examples/datagrid/store/hibernate/hibernate.cfg.xml @@ -26,8 +26,11 @@ --> <hibernate-configuration> <session-factory> - <!-- Database connection settings (private in-memory database). --> - <property name="connection.url">jdbc:h2:mem:example;DB_CLOSE_DELAY=-1</property> + <!-- Database connection URL. --> + <property name="connection.url">jdbc:h2:tcp://localhost/mem:ExampleDb</property> + + <!-- Database connection username. --> + <property name="connection.username">sa</property> <!-- Only validate the database schema on startup in production mode. --> <property name="hbm2ddl.auto">update</property> http://git-wip-us.apache.org/repos/asf/ignite/blob/e1b2cf28/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java new file mode 100644 index 0000000..c4b52bb --- /dev/null +++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringPersonStore.java @@ -0,0 +1,118 @@ +/* + * 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.examples.datagrid.store.spring; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.concurrent.atomic.AtomicInteger; +import javax.cache.Cache; +import javax.cache.integration.CacheLoaderException; +import javax.sql.DataSource; +import org.apache.ignite.IgniteException; +import org.apache.ignite.cache.store.CacheStore; +import org.apache.ignite.cache.store.CacheStoreAdapter; +import org.apache.ignite.examples.model.Person; +import org.apache.ignite.lang.IgniteBiInClosure; +import org.h2.jdbcx.JdbcConnectionPool; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowCallbackHandler; +import org.springframework.jdbc.core.RowMapper; + +/** + * Example of {@link CacheStore} implementation that uses JDBC + * transaction with cache transactions and maps {@link Long} to {@link Person}. + */ +public class CacheSpringPersonStore extends CacheStoreAdapter<Long, Person> { + /** Data source. */ + public static final DataSource DATA_SRC = + JdbcConnectionPool.create("jdbc:h2:tcp://localhost/mem:ExampleDb", "sa", ""); + + /** Spring JDBC template. */ + private JdbcTemplate jdbcTemplate; + + /** + * Constructor. + * + * @throws IgniteException If failed. + */ + public CacheSpringPersonStore() throws IgniteException { + jdbcTemplate = new JdbcTemplate(DATA_SRC); + } + + /** {@inheritDoc} */ + @Override public Person load(Long key) { + System.out.println(">>> Store load [key=" + key + ']'); + + try { + return jdbcTemplate.queryForObject("select * from PERSON where id = ?", new RowMapper<Person>() { + @Override public Person mapRow(ResultSet rs, int rowNum) throws SQLException { + return new Person(rs.getLong(1), rs.getString(2), rs.getString(3)); + } + }, key); + } + catch (EmptyResultDataAccessException ignored) { + return null; + } + } + + /** {@inheritDoc} */ + @Override public void write(Cache.Entry<? extends Long, ? extends Person> entry) { + Long key = entry.getKey(); + Person val = entry.getValue(); + + System.out.println(">>> Store write [key=" + key + ", val=" + val + ']'); + + int updated = jdbcTemplate.update("update PERSON set first_name = ?, last_name = ? where id = ?", + val.firstName, val.lastName, val.id); + + if (updated == 0) { + jdbcTemplate.update("insert into PERSON (id, first_name, last_name) values (?, ?, ?)", + val.id, val.firstName, val.lastName); + } + } + + /** {@inheritDoc} */ + @Override public void delete(Object key) { + System.out.println(">>> Store delete [key=" + key + ']'); + + jdbcTemplate.update("delete from PERSON where id = ?", key); + } + + /** {@inheritDoc} */ + @Override public void loadCache(final IgniteBiInClosure<Long, Person> clo, Object... args) { + if (args == null || args.length == 0 || args[0] == null) + throw new CacheLoaderException("Expected entry count parameter is not provided."); + + int entryCnt = (Integer)args[0]; + + final AtomicInteger cnt = new AtomicInteger(); + + jdbcTemplate.query("select * from PERSON limit ?", new RowCallbackHandler() { + @Override public void processRow(ResultSet rs) throws SQLException { + Person person = new Person(rs.getLong(1), rs.getString(2), rs.getString(3)); + + clo.apply(person.id, person); + + cnt.incrementAndGet(); + } + }, entryCnt); + + System.out.println(">>> Loaded " + cnt + " values into cache."); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/e1b2cf28/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.java new file mode 100644 index 0000000..5380fce --- /dev/null +++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/CacheSpringStoreExample.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.examples.datagrid.store.spring; + +import java.util.UUID; +import javax.cache.configuration.Factory; +import javax.cache.configuration.FactoryBuilder; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteException; +import org.apache.ignite.Ignition; +import org.apache.ignite.cache.store.CacheStoreSessionListener; +import org.apache.ignite.cache.store.spring.CacheSpringStoreSessionListener; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.examples.ExampleNodeStartup; +import org.apache.ignite.examples.ExamplesUtils; +import org.apache.ignite.examples.model.Person; +import org.apache.ignite.examples.util.DbH2ServerStartup; +import org.apache.ignite.transactions.Transaction; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; + +/** + * Demonstrates usage of cache with underlying persistent store configured. + * <p> + * This example uses {@link CacheSpringPersonStore} as a persistent store. + * <p> + * To start the example, you should: + * <ul> + * <li>Start H2 database TCP server using {@link DbH2ServerStartup}.</li> + * <li>Start a few nodes using {@link ExampleNodeStartup}.</li> + * <li>Start example using {@link CacheSpringStoreExample}.</li> + * </ul> + * <p> + * Remote nodes can be started with {@link ExampleNodeStartup} in another JVM which will + * start node with {@code examples/config/example-ignite.xml} configuration. + */ +public class CacheSpringStoreExample { + /** Cache name. */ + private static final String CACHE_NAME = CacheSpringStoreExample.class.getSimpleName(); + + /** Heap size required to run this example. */ + public static final int MIN_MEMORY = 1024 * 1024 * 1024; + + /** Number of entries to load. */ + private static final int ENTRY_COUNT = 100_000; + + /** Global person ID to use across entire example. */ + private static final Long id = Math.abs(UUID.randomUUID().getLeastSignificantBits()); + + /** + * Executes example. + * + * @param args Command line arguments, none required. + * @throws IgniteException If example execution failed. + */ + public static void main(String[] args) throws IgniteException { + ExamplesUtils.checkMinMemory(MIN_MEMORY); + + // To start ignite with desired configuration uncomment the appropriate line. + try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) { + System.out.println(); + System.out.println(">>> Cache store example started."); + + CacheConfiguration<Long, Person> cacheCfg = new CacheConfiguration<>(CACHE_NAME); + + // Set atomicity as transaction, since we are showing transactions in example. + cacheCfg.setAtomicityMode(TRANSACTIONAL); + + // Configure Spring store. + cacheCfg.setCacheStoreFactory(FactoryBuilder.factoryOf(CacheSpringPersonStore.class)); + + // Configure Spring session listener. + cacheCfg.setCacheStoreSessionListenerFactories(new Factory<CacheStoreSessionListener>() { + @Override public CacheStoreSessionListener create() { + CacheSpringStoreSessionListener lsnr = new CacheSpringStoreSessionListener(); + + lsnr.setDataSource(CacheSpringPersonStore.DATA_SRC); + + return lsnr; + } + }); + + cacheCfg.setReadThrough(true); + cacheCfg.setWriteThrough(true); + + try (IgniteCache<Long, Person> cache = ignite.getOrCreateCache(cacheCfg)) { + // Make initial cache loading from persistent store. This is a + // distributed operation and will call CacheStore.loadCache(...) + // method on all nodes in topology. + loadCache(cache); + + // Start transaction and execute several cache operations with + // read/write-through to persistent store. + executeTransaction(cache); + } + } + } + + /** + * Makes initial cache loading. + * + * @param cache Cache to load. + */ + private static void loadCache(IgniteCache<Long, Person> cache) { + long start = System.currentTimeMillis(); + + // Start loading cache from persistent store on all caching nodes. + cache.loadCache(null, ENTRY_COUNT); + + long end = System.currentTimeMillis(); + + System.out.println(">>> Loaded " + cache.size() + " keys with backups in " + (end - start) + "ms."); + } + + /** + * Executes transaction with read/write-through to persistent store. + * + * @param cache Cache to execute transaction on. + */ + private static void executeTransaction(IgniteCache<Long, Person> cache) { + try (Transaction tx = Ignition.ignite().transactions().txStart()) { + Person val = cache.get(id); + + System.out.println("Read value: " + val); + + val = cache.getAndPut(id, new Person(id, "Isaac", "Newton")); + + System.out.println("Overwrote old value: " + val); + + val = cache.get(id); + + System.out.println("Read value: " + val); + + tx.commit(); + } + + System.out.println("Read value after commit: " + cache.get(id)); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/e1b2cf28/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/package-info.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/package-info.java b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/package-info.java new file mode 100644 index 0000000..211239f --- /dev/null +++ b/examples/src/main/java/org/apache/ignite/examples/datagrid/store/spring/package-info.java @@ -0,0 +1,22 @@ +/* + * 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 description. --> + * Contains Spring-based cache store implementation. + */ +package org.apache.ignite.examples.datagrid.store.spring;