http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExample.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExample.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExample.java new file mode 100644 index 0000000..471bfd6 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExample.java @@ -0,0 +1,203 @@ +/* + * 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.examples8.datagrid.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.examples8.*; +import org.hibernate.*; +import org.hibernate.cfg.*; +import org.hibernate.service.*; +import org.hibernate.stat.*; + +import java.net.*; +import java.util.*; + +/** + * This example demonstrates the use of Ignite In-Memory Data Ignite cluster as a Hibernate + * Second-Level cache provider. + * <p> + * The Hibernate Second-Level cache (or "L2 cache" shortly) lets you significantly + * reduce the number of requests to the underlying SQL database. Because database + * access is known to be an expansive operation, using L2 cache may improve + * performance dramatically. + * <p> + * This example defines 2 entity classes: {@link org.apache.ignite.examples8.datagrid.hibernate.User} and {@link org.apache.ignite.examples.datagrid.hibernate.Post}, with + * 1 <-> N relation, and marks them with appropriate annotations for Hibernate + * object-relational mapping to SQL tables of an underlying H2 in-memory database. + * The example launches node in the same JVM and registers it in + * Hibernate configuration as an L2 cache implementation. It then stores and + * queries instances of the entity classes to and from the database, having + * Hibernate SQL output, L2 cache statistics output, and Ignite cache metrics + * output enabled. + * <p> + * When running example, it's easy to notice that when an object is first + * put into a database, the L2 cache is not used and it's contents is empty. + * However, when an object is first read from the database, it is immediately + * stored in L2 cache (which is Ignite In-Memory Data Ignite cluster in fact), which can + * be seen in stats output. Further requests of the same object only read the data + * from L2 cache and do not hit the database. + * <p> + * In this example, the Hibernate query cache is also enabled. Query cache lets you + * avoid hitting the database in case of repetitive queries with the same parameter + * values. You may notice that when the example runs the same query repeatedly in + * loop, only the first query hits the database and the successive requests take the + * data from L2 cache. + * <p> + * Note: this example uses {@link org.hibernate.cache.spi.access.AccessType#READ_ONLY} L2 cache access type, but you + * can experiment with other access types by modifying the Hibernate configuration file + * {@code IGNITE_HOME/examples/config/hibernate/example-hibernate-L2-cache.xml}, used by the example. + * <p> + * Remote nodes should always be started using {@link HibernateL2CacheExampleNodeStartup} + */ +public class HibernateL2CacheExample { + /** JDBC URL for backing database (an H2 in-memory database is used). */ + private static final String JDBC_URL = "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1"; + + /** Path to hibernate configuration file (will be resolved from application {@code CLASSPATH}). */ + private static final String HIBERNATE_CFG = "hibernate/example-hibernate-L2-cache.xml"; + + /** Entity names for stats output. */ + private static final List<String> ENTITY_NAMES = + Arrays.asList(User.class.getName(), Post.class.getName(), User.class.getName() + ".posts"); + + /** + * Executes example. + * + * @param args Command line arguments, none required. + * @throws org.apache.ignite.IgniteException If example execution failed. + */ + public static void main(String[] args) throws IgniteException { + // Start the node, run the example, and stop the node when finished. + try (Ignite ignite = Ignition.start(HibernateL2CacheExampleNodeStartup.configuration())) { + // We use a single session factory, but create a dedicated session + // for each transaction or query. This way we ensure that L1 cache + // is not used (L1 cache has per-session scope only). + System.out.println(); + System.out.println(">>> Hibernate L2 cache example started."); + + URL hibernateCfg = ExamplesUtils.url(HIBERNATE_CFG); + + SessionFactory sesFactory = createHibernateSessionFactory(hibernateCfg); + + System.out.println(); + System.out.println(">>> Creating objects."); + + final long userId; + + Session ses = sesFactory.openSession(); + + try { + Transaction tx = ses.beginTransaction(); + + User user = new User("jedi", "Luke", "Skywalker"); + + user.getPosts().add(new Post(user, "Let the Force be with you.")); + + ses.save(user); + + tx.commit(); + + // Create a user object, store it in DB, and save the database-generated + // object ID. You may try adding more objects in a similar way. + userId = user.getId(); + } + finally { + ses.close(); + } + + // Output L2 cache and Ignite cache stats. You may notice that + // at this point the object is not yet stored in L2 cache, because + // the read was not yet performed. + printStats(sesFactory); + + System.out.println(); + System.out.println(">>> Querying object by ID."); + + // Query user by ID several times. First time we get an L2 cache + // miss, and the data is queried from DB, but it is then stored + // in cache and successive queries hit the cache and return + // immediately, no SQL query is made. + for (int i = 0; i < 3; i++) { + ses = sesFactory.openSession(); + + try { + Transaction tx = ses.beginTransaction(); + + User user = (User)ses.get(User.class, userId); + + System.out.println("User: " + user); + + for (Post post : user.getPosts()) + System.out.println("\tPost: " + post); + + tx.commit(); + } + finally { + ses.close(); + } + } + + // Output the stats. We should see 1 miss and 2 hits for + // User and Collection object (stored separately in L2 cache). + // The Post is loaded with the collection, so it won't imply + // a miss. + printStats(sesFactory); + } + } + + /** + * Creates a new Hibernate {@link org.hibernate.SessionFactory} using a programmatic + * configuration. + * + * @param hibernateCfg Hibernate configuration file. + * @return New Hibernate {@link org.hibernate.SessionFactory}. + */ + private static SessionFactory createHibernateSessionFactory(URL hibernateCfg) { + ServiceRegistryBuilder builder = new ServiceRegistryBuilder(); + + builder.applySetting("hibernate.connection.url", JDBC_URL); + builder.applySetting("hibernate.show_sql", true); + + return new Configuration() + .configure(hibernateCfg) + .buildSessionFactory(builder.buildServiceRegistry()); + } + + /** + * Prints Hibernate L2 cache statistics to standard output. + * + * @param sesFactory Hibernate {@link org.hibernate.SessionFactory}, for which to print + * statistics. + */ + private static void printStats(SessionFactory sesFactory) { + System.out.println("=== Hibernate L2 cache statistics ==="); + + for (String entityName : ENTITY_NAMES) { + System.out.println("\tEntity: " + entityName); + + SecondLevelCacheStatistics stats = + sesFactory.getStatistics().getSecondLevelCacheStatistics(entityName); + + System.out.println("\t\tL2 cache entries: " + stats.getEntries()); + System.out.println("\t\tHits: " + stats.getHitCount()); + System.out.println("\t\tMisses: " + stats.getMissCount()); + } + + System.out.println("====================================="); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExampleNodeStartup.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExampleNodeStartup.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExampleNodeStartup.java new file mode 100644 index 0000000..bfab641 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/HibernateL2CacheExampleNodeStartup.java @@ -0,0 +1,97 @@ +/* + * 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.examples8.datagrid.hibernate; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.configuration.*; +import org.apache.ignite.spi.discovery.tcp.*; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*; + +import java.util.*; + +import static org.apache.ignite.cache.CacheAtomicityMode.*; +import static org.apache.ignite.cache.CacheMode.*; +import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*; + +/** + * Starts up an empty node with example cache configuration. + */ +public class HibernateL2CacheExampleNodeStartup { + /** + * Start up an empty node with specified cache configuration. + * + * @param args Command line arguments, none required. + * @throws org.apache.ignite.IgniteException If example execution failed. + */ + public static void main(String[] args) throws IgniteException { + Ignition.start(configuration()); + } + + /** + * Create Ignite configuration with IGFS and enabled IPC. + * + * @return Ignite configuration. + * @throws org.apache.ignite.IgniteException If configuration creation failed. + */ + public static IgniteConfiguration configuration() throws IgniteException { + IgniteConfiguration cfg = new IgniteConfiguration(); + + cfg.setGridName("hibernate-grid"); + cfg.setLocalHost("127.0.0.1"); + cfg.setConnectorConfiguration(null); + + TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); + + TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder(); + + ipFinder.setAddresses(Collections.singletonList("127.0.0.1:47500..47509")); + + discoSpi.setIpFinder(ipFinder); + + cfg.setDiscoverySpi(discoSpi); + + cfg.setCacheConfiguration( + cacheConfiguration("org.hibernate.cache.spi.UpdateTimestampsCache", ATOMIC), + cacheConfiguration("org.hibernate.cache.internal.StandardQueryCache", ATOMIC), + cacheConfiguration("org.apache.ignite.examples8.datagrid.hibernate.User", TRANSACTIONAL), + cacheConfiguration("org.apache.ignite.examples8.datagrid.hibernate.User.posts", TRANSACTIONAL), + cacheConfiguration("org.apache.ignite.examples8.datagrid.hibernate.Post", TRANSACTIONAL) + ); + + return cfg; + } + + /** + * Create cache configuration. + * + * @param name Cache name. + * @param atomicityMode Atomicity mode. + * @return Cache configuration. + */ + private static CacheConfiguration cacheConfiguration(String name, CacheAtomicityMode atomicityMode) { + CacheConfiguration ccfg = new CacheConfiguration(); + + ccfg.setName(name); + ccfg.setCacheMode(PARTITIONED); + ccfg.setAtomicityMode(atomicityMode); + ccfg.setWriteSynchronizationMode(FULL_SYNC); + + return ccfg; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/Post.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/Post.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/Post.java new file mode 100644 index 0000000..cd77149 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/Post.java @@ -0,0 +1,126 @@ +/* + * 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.examples8.datagrid.hibernate; + +import javax.persistence.*; +import java.util.*; + +/** + * An entity class representing a post, that a + * {@link org.apache.ignite.examples8.datagrid.hibernate.User} has made on some public service. + */ +@Entity +class Post { + /** ID. */ + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private long id; + + /** Author. */ + @ManyToOne + private User author; + + /** Text. */ + private String text; + + /** Created timestamp. */ + private Date created; + + /** + * Default constructor (required by Hibernate). + */ + Post() { + // No-op. + } + + /** + * Constructor. + * + * @param author Author. + * @param text Text. + */ + Post(User author, String text) { + this.author = author; + this.text = text; + created = new Date(); + } + + /** + * @return ID. + */ + public long getId() { + return id; + } + + /** + * @param id New ID. + */ + public void setId(long id) { + this.id = id; + } + + /** + * @return Author. + */ + public User getAuthor() { + return author; + } + + /** + * @param author New author. + */ + public void setAuthor(User author) { + this.author = author; + } + + /** + * @return Text. + */ + public String getText() { + return text; + } + + /** + * @param text New text. + */ + public void setText(String text) { + this.text = text; + } + + /** + * @return Created timestamp. + */ + public Date getCreated() { + return (Date)created.clone(); + } + + /** + * @param created New created timestamp. + */ + public void setCreated(Date created) { + this.created = (Date)created.clone(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "Post [id=" + id + + ", text=" + text + + ", created=" + created + + ']'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/User.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/User.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/User.java new file mode 100644 index 0000000..8f83b74 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/User.java @@ -0,0 +1,151 @@ +/* + * 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.examples8.datagrid.hibernate; + +import org.hibernate.annotations.*; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.*; +import java.util.*; + +/** + * A user entity class. Represents a user of some public service, + * having a number of personal information fields as well as a + * number of posts written. + */ +@Entity +class User { + /** ID. */ + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private long id; + + /** Login. */ + @NaturalId + private String login; + + /** First name. */ + private String firstName; + + /** Last name. */ + private String lastName; + + /** Posts. */ + @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) + private Set<Post> posts = new HashSet<>(); + + /** + * Default constructor (required by Hibernate). + */ + User() { + // No-op. + } + + /** + * Constructor. + * + * @param login Login. + * @param firstName First name. + * @param lastName Last name. + */ + User(String login, String firstName, String lastName) { + this.login = login; + this.firstName = firstName; + this.lastName = lastName; + } + + /** + * @return ID. + */ + public long getId() { + return id; + } + + /** + * @param id New ID. + */ + public void setId(long id) { + this.id = id; + } + + /** + * @return Login. + */ + public String getLogin() { + return login; + } + + /** + * @param login New login. + */ + public void setLogin(String login) { + this.login = login; + } + + /** + * @return First name. + */ + public String getFirstName() { + return firstName; + } + + /** + * @param firstName New first name. + */ + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + /** + * @return Last name. + */ + public String getLastName() { + return lastName; + } + + /** + * @param lastName New last name. + */ + public void setLastName(String lastName) { + this.lastName = lastName; + } + + /** + * @return Posts. + */ + public Set<Post> getPosts() { + return posts; + } + + /** + * @param posts New posts. + */ + public void setPosts(Set<Post> posts) { + this.posts = posts; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "User [id=" + id + + ", login=" + login + + ", firstName=" + firstName + + ", lastName=" + lastName + + ']'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/package.html ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/package.html b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/package.html new file mode 100644 index 0000000..aa0a376 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/hibernate/package.html @@ -0,0 +1,24 @@ +<!-- + 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. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> + <!-- Package description. --> + Hibernate example. +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/package.html ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/package.html b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/package.html new file mode 100644 index 0000000..693f16b --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/package.html @@ -0,0 +1,24 @@ +<!-- + 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. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> + <!-- Package description. --> + Demonstrates data ignite cache usage. +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/CacheStarSchemaExample.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/CacheStarSchemaExample.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/CacheStarSchemaExample.java new file mode 100644 index 0000000..9018355 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/CacheStarSchemaExample.java @@ -0,0 +1,230 @@ +/* + * 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.examples8.datagrid.starschema; + +import org.apache.ignite.*; +import org.apache.ignite.cache.query.*; + +import javax.cache.*; +import java.util.*; +import java.util.concurrent.*; + +import static org.apache.ignite.cache.query.Query.*; + +/** + * <a href="http://en.wikipedia.org/wiki/Snowflake_schema">Snowflake Schema</a> is a logical + * arrangement of data in which data is split into {@code dimensions} and {@code facts}. + * <i>Dimensions</i> can be referenced or joined by other <i>dimensions</i> or <i>facts</i>, + * however, <i>facts</i> are generally not referenced by other facts. You can view <i>dimensions</i> + * as your master or reference data, while <i>facts</i> are usually large data sets of events or + * other objects that continuously come into the system and may change frequently. In Ignite + * such architecture is supported via cross-cache queries. By storing <i>dimensions</i> in + * {@link org.apache.ignite.cache.CacheMode#REPLICATED REPLICATED} caches and <i>facts</i> in much larger + * {@link org.apache.ignite.cache.CacheMode#PARTITIONED PARTITIONED} caches you can freely execute distributed joins across + * your whole in-memory data ignite cluster, thus querying your in memory data without any limitations. + * <p> + * In this example we have two <i>dimensions</i>, {@link DimProduct} and {@link org.apache.ignite.examples8.datagrid.starschema.DimStore} and + * one <i>fact</i> - {@link org.apache.ignite.examples8.datagrid.starschema.FactPurchase}. Queries are executed by joining dimensions and facts + * in various ways. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: {@code 'ignite.{sh|bat} examples/config/example-cache.xml'}. + * <p> + * Alternatively you can run {@link org.apache.ignite.examples8.datagrid.CacheNodeStartup} in another JVM which will + * start node with {@code examples/config/example-cache.xml} configuration. + */ +public class CacheStarSchemaExample { + /** Partitioned cache name. */ + private static final String PARTITIONED_CACHE_NAME = "partitioned"; + + /** Replicated cache name. */ + private static final String REPLICATED_CACHE_NAME = "replicated"; + + /** ID generator. */ + private static int idGen = (int)System.currentTimeMillis(); + + /** DimStore data. */ + private static Map<Integer, DimStore> dataStore = new HashMap<>(); + + /** DimProduct data. */ + private static Map<Integer, DimProduct> dataProduct = new HashMap<>(); + + /** + * Executes example. + * + * @param args Command line arguments, none required. + */ + public static void main(String[] args) { + Ignite ignite = Ignition.start("examples/config/example-cache.xml"); + + System.out.println(); + System.out.println(">>> Cache star schema example started."); + + // Clean up caches on all nodes before run. + ignite.jcache(PARTITIONED_CACHE_NAME).clear(); + ignite.jcache(REPLICATED_CACHE_NAME).clear(); + + try { + populateDimensions(); + populateFacts(); + + queryStorePurchases(); + queryProductPurchases(); + } + finally { + Ignition.stop(false); + } + } + + /** + * Populate cache with {@code 'dimensions'} which in our case are + * {@link org.apache.ignite.examples8.datagrid.starschema.DimStore} and {@link DimProduct} instances. + * + * @throws org.apache.ignite.IgniteException If failed. + */ + private static void populateDimensions() throws IgniteException { + IgniteCache<Integer, Object> cache = Ignition.ignite().jcache(REPLICATED_CACHE_NAME); + + DimStore store1 = new DimStore(idGen++, "Store1", "12345", "321 Chilly Dr, NY"); + DimStore store2 = new DimStore(idGen++, "Store2", "54321", "123 Windy Dr, San Francisco"); + + // Populate stores. + cache.put(store1.getId(), store1); + cache.put(store2.getId(), store2); + + dataStore.put(store1.getId(), store1); + dataStore.put(store2.getId(), store2); + + // Populate products + for (int i = 0; i < 20; i++) { + int id = idGen++; + + DimProduct product = new DimProduct(id, "Product" + i, i + 1, (i + 1) * 10); + + cache.put(id, product); + + dataProduct.put(id, product); + } + } + + /** + * Populate cache with {@code 'facts'}, which in our case are {@link org.apache.ignite.examples8.datagrid.starschema.FactPurchase} objects. + * + * @throws org.apache.ignite.IgniteException If failed. + */ + private static void populateFacts() throws IgniteException { + IgniteCache<Integer, Object> factCache = Ignition.ignite().jcache(PARTITIONED_CACHE_NAME); + + for (int i = 0; i < 100; i++) { + int id = idGen++; + + DimStore store = rand(dataStore.values()); + DimProduct prod = rand(dataProduct.values()); + + factCache.put(id, new FactPurchase(id, prod.getId(), store.getId(), (i + 1))); + } + } + + /** + * Query all purchases made at a specific store. This query uses cross-cache joins + * between {@link org.apache.ignite.examples8.datagrid.starschema.DimStore} objects stored in {@code 'replicated'} cache and + * {@link org.apache.ignite.examples8.datagrid.starschema.FactPurchase} objects stored in {@code 'partitioned'} cache. + */ + private static void queryStorePurchases() { + IgniteCache<Integer, FactPurchase> factCache = Ignition.ignite().jcache(PARTITIONED_CACHE_NAME); + + // All purchases for store1. + // ======================== + + // Create cross cache query to get all purchases made at store1. + QueryCursor<Cache.Entry<Integer, FactPurchase>> storePurchases = factCache.query(sql( + FactPurchase.class, + "from \"replicated\".DimStore, \"partitioned\".FactPurchase " + + "where DimStore.id=FactPurchase.storeId and DimStore.name=?").setArgs("Store1")); + + printQueryResults("All purchases made at store1:", storePurchases.getAll()); + } + + /** + * Query all purchases made at a specific store for 3 specific products. + * This query uses cross-cache joins between {@link org.apache.ignite.examples8.datagrid.starschema.DimStore}, {@link DimProduct} + * objects stored in {@code 'replicated'} cache and {@link org.apache.ignite.examples8.datagrid.starschema.FactPurchase} objects + * stored in {@code 'partitioned'} cache. + * + * @throws org.apache.ignite.IgniteException If failed. + */ + private static void queryProductPurchases() { + IgniteCache<Integer, FactPurchase> factCache = Ignition.ignite().jcache(PARTITIONED_CACHE_NAME); + + // All purchases for certain product made at store2. + // ================================================= + + DimProduct p1 = rand(dataProduct.values()); + DimProduct p2 = rand(dataProduct.values()); + DimProduct p3 = rand(dataProduct.values()); + + System.out.println("IDs of products [p1=" + p1.getId() + ", p2=" + p2.getId() + ", p3=" + p3.getId() + ']'); + + // Create cross cache query to get all purchases made at store2 + // for specified products. + QueryCursor<Cache.Entry<Integer, FactPurchase>> prodPurchases = factCache.query(sql( + FactPurchase.class, + "from \"replicated\".DimStore, \"replicated\".DimProduct, \"partitioned\".FactPurchase " + + "where DimStore.id=FactPurchase.storeId and DimProduct.id=FactPurchase.productId " + + "and DimStore.name=? and DimProduct.id in(?, ?, ?)") + .setArgs("Store2", p1.getId(), p2.getId(), p3.getId())); + + printQueryResults("All purchases made at store2 for 3 specific products:", prodPurchases.getAll()); + } + + /** + * Print query results. + * + * @param msg Initial message. + * @param res Results to print. + */ + private static <V> void printQueryResults(String msg, Iterable<Cache.Entry<Integer, V>> res) { + System.out.println(msg); + + for (Cache.Entry<?, ?> e : res) + System.out.println(" " + e.getValue().toString()); + } + + /** + * Gets random value from given collection. + * + * @param c Input collection (no {@code null} and not empty). + * @return Random value from the input collection. + */ + @SuppressWarnings("UnusedDeclaration") + private static <T> T rand(Collection<? extends T> c) { + if (c == null) + throw new IllegalArgumentException(); + + int n = ThreadLocalRandom.current().nextInt(c.size()); + + int i = 0; + + for (T t : c) { + if (i++ == n) + return t; + } + + throw new ConcurrentModificationException(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimProduct.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimProduct.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimProduct.java new file mode 100644 index 0000000..df42836 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimProduct.java @@ -0,0 +1,100 @@ +/* + * 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.examples8.datagrid.starschema; + +import org.apache.ignite.cache.query.annotations.*; + +/** + * Represents a product available for purchase. In our {@code snowflake} schema a {@code product} + * is a {@code 'dimension'} and will be cached in {@link org.apache.ignite.cache.CacheMode#REPLICATED} + * cache. + */ +public class DimProduct { + /** Primary key. */ + @QuerySqlField(index = true) + private int id; + + /** Product name. */ + private String name; + + /** Product list price. */ + @QuerySqlField + private float price; + + /** Available product quantity. */ + private int qty; + + /** + * Constructs a product instance. + * + * @param id Product ID. + * @param name Product name. + * @param price Product list price. + * @param qty Available product quantity. + */ + public DimProduct(int id, String name, float price, int qty) { + this.id = id; + this.name = name; + this.price = price; + this.qty = qty; + } + + /** + * Gets product ID. + * + * @return Product ID. + */ + public int getId() { + return id; + } + + /** + * Gets product name. + * + * @return Product name. + */ + public String getName() { + return name; + } + + /** + * Gets product list price. + * + * @return Product list price. + */ + public float getPrice() { + return price; + } + + /** + * Gets available product quantity. + * + * @return Available product quantity. + */ + public int getQuantity() { + return qty; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "DimProduct [id=" + id + + ", name=" + name + + ", price=" + price + + ", qty=" + qty + ']'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimStore.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimStore.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimStore.java new file mode 100644 index 0000000..6d13552 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/DimStore.java @@ -0,0 +1,100 @@ +/* + * 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.examples8.datagrid.starschema; + +import org.apache.ignite.cache.query.annotations.*; + +/** + * Represents a physical store location. In our {@code snowflake} schema a {@code store} + * is a {@code 'dimension'} and will be cached in {@link org.apache.ignite.cache.CacheMode#REPLICATED} + * cache. + */ +public class DimStore { + /** Primary key. */ + @QuerySqlField(index = true) + private int id; + + /** Store name. */ + @QuerySqlField + private String name; + + /** Zip code. */ + private String zip; + + /** Address. */ + private String addr; + + /** + * Constructs a store instance. + * + * @param id Store ID. + * @param name Store name. + * @param zip Store zip code. + * @param addr Store address. + */ + public DimStore(int id, String name, String zip, String addr) { + this.id = id; + this.name = name; + this.zip = zip; + this.addr = addr; + } + + /** + * Gets store ID. + * + * @return Store ID. + */ + public int getId() { + return id; + } + + /** + * Gets store name. + * + * @return Store name. + */ + public String getName() { + return name; + } + + /** + * Gets store zip code. + * + * @return Store zip code. + */ + public String getZip() { + return zip; + } + + /** + * Gets store address. + * + * @return Store address. + */ + public String getAddress() { + return addr; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "DimStore [id=" + id + + ", name=" + name + + ", zip=" + zip + + ", addr=" + addr + ']'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/FactPurchase.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/FactPurchase.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/FactPurchase.java new file mode 100644 index 0000000..1846c82 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/FactPurchase.java @@ -0,0 +1,102 @@ +/* + * 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.examples8.datagrid.starschema; + +import org.apache.ignite.cache.query.annotations.*; + +/** + * Represents a purchase record. In our {@code snowflake} schema purchase + * is a {@code 'fact'} and will be cached in larger {@link org.apache.ignite.cache.CacheMode#PARTITIONED} + * cache. + */ +public class FactPurchase { + /** Primary key. */ + @QuerySqlField(index = true) + private int id; + + /** Foreign key to store at which purchase occurred. */ + @QuerySqlField + private int storeId; + + /** Foreign key to purchased product. */ + @QuerySqlField + private int productId; + + /** Purchase price. */ + @QuerySqlField + private float purchasePrice; + + /** + * Constructs a purchase record. + * + * @param id Purchase ID. + * @param productId Purchased product ID. + * @param storeId Store ID. + * @param purchasePrice Purchase price. + */ + public FactPurchase(int id, int productId, int storeId, float purchasePrice) { + this.id = id; + this.productId = productId; + this.storeId = storeId; + this.purchasePrice = purchasePrice; + } + + /** + * Gets purchase ID. + * + * @return Purchase ID. + */ + public int getId() { + return id; + } + + /** + * Gets purchased product ID. + * + * @return Product ID. + */ + public int getProductId() { + return productId; + } + + /** + * Gets ID of store at which purchase was made. + * + * @return Store ID. + */ + public int getStoreId() { + return storeId; + } + + /** + * Gets purchase price. + * + * @return Purchase price. + */ + public float getPurchasePrice() { + return purchasePrice; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "FactPurchase [id=" + id + + ", productId=" + productId + + ", storeId=" + storeId + + ", purchasePrice=" + purchasePrice + ']'; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/package.html ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/package.html b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/package.html new file mode 100644 index 0000000..2ff779e --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/starschema/package.html @@ -0,0 +1,24 @@ +<!-- + 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. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> + <!-- Package description. --> + Demonstrates distributed SQL joins over ignite using Snowflake schema. +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheNodeWithStoreStartup.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheNodeWithStoreStartup.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheNodeWithStoreStartup.java new file mode 100644 index 0000000..01931de --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheNodeWithStoreStartup.java @@ -0,0 +1,148 @@ +/* + * 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.examples8.datagrid.store; + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.cache.store.*; +import org.apache.ignite.configuration.*; +import org.apache.ignite.examples8.datagrid.store.dummy.*; +import org.apache.ignite.examples8.datagrid.store.hibernate.*; +import org.apache.ignite.examples8.datagrid.store.jdbc.*; +import org.apache.ignite.examples8.datagrid.store.model.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.spi.discovery.tcp.*; +import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.*; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*; + +import javax.cache.configuration.*; +import java.sql.*; +import java.util.*; + +import static org.apache.ignite.cache.CacheAtomicityMode.*; + +/** + * Starts up an empty node with example cache and store configuration. + */ +public class CacheNodeWithStoreStartup { + /** Use org.apache.ignite.examples8.datagrid.store.dummy.CacheDummyPersonStore to run example. */ + public static final String DUMMY = "DUMMY"; + + /** Use org.apache.ignite.examples8.datagrid.store.jdbc.CacheJdbcPersonStore to run example. */ + public static final String SIMPLE_JDBC = "SIMPLE_JDBC"; + + /** Use org.apache.ignite.examples8.datagrid.store.hibernate.CacheHibernatePersonStore to run example. */ + public static final String HIBERNATE = "HIBERNATE"; + + /** Use org.apache.ignite.examples8.datagrid.store.jdbc.CacheJdbcPojoPersonStore to run example. */ + public static final String AUTO = "AUTO"; + + /** Store to use. */ + public static final String STORE = DUMMY; + + /** + * Start up an empty node with specified cache configuration. + * + * @param args Command line arguments, none required. + * @throws org.apache.ignite.IgniteException If example execution failed. + */ + public static void main(String[] args) throws IgniteException { + Ignition.start(configure()); + } + + /** + * Configure ignite. + * + * @return Ignite configuration. + * @throws org.apache.ignite.IgniteException If failed. + */ + public static IgniteConfiguration configure() throws IgniteException { + IgniteConfiguration cfg = new IgniteConfiguration(); + + cfg.setLocalHost("127.0.0.1"); + + // Discovery SPI. + TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); + + TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder(); + + ipFinder.setAddresses(Arrays.asList("127.0.0.1:47500..47509")); + + discoSpi.setIpFinder(ipFinder); + + CacheConfiguration<Long, Person> cacheCfg = new CacheConfiguration<>(); + + // Set atomicity as transaction, since we are showing transactions in example. + cacheCfg.setAtomicityMode(TRANSACTIONAL); + + // Set query indexing enabled for use query in example. + cacheCfg.setQueryIndexEnabled(true); + + CacheStore<Long, Person> store; + + switch (STORE) { + case DUMMY: + store = new CacheDummyPersonStore(); + break; + + case SIMPLE_JDBC: + store = new CacheJdbcPersonStore(); + break; + + case HIBERNATE: + store = new CacheHibernatePersonStore(); + break; + + default: + store = new CacheJdbcPojoPersonStore(); + cacheCfg.setTypeMetadata(typeMetadata()); + break; + } + + cacheCfg.setCacheStoreFactory(new FactoryBuilder.SingletonFactory<>(store)); + cacheCfg.setReadThrough(true); + cacheCfg.setWriteThrough(true); + + cfg.setDiscoverySpi(discoSpi); + cfg.setCacheConfiguration(cacheCfg); + + return cfg; + } + + /** + * @return Type mapping description. + */ + private static Collection<CacheTypeMetadata> typeMetadata() { + CacheTypeMetadata tm = new CacheTypeMetadata(); + + tm.setDatabaseTable("PERSON"); + + tm.setKeyType("java.lang.Long"); + tm.setValueType("org.apache.ignite.examples8.datagrid.store.model.Person"); + + tm.setKeyFields(F.asList(new CacheTypeFieldMetadata("ID", Types.BIGINT, "id", Long.class))); + + tm.setValueFields(F.asList( + new CacheTypeFieldMetadata("ID", Types.BIGINT, "id", long.class), + new CacheTypeFieldMetadata("FIRST_NAME", Types.VARCHAR, "firstName", String.class), + new CacheTypeFieldMetadata("LAST_NAME", Types.VARCHAR, "lastName", String.class) + )); + + return F.asList(tm); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreExample.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreExample.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreExample.java new file mode 100644 index 0000000..0943a23 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreExample.java @@ -0,0 +1,107 @@ +/* + * 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.examples8.datagrid.store; + +import org.apache.ignite.*; +import org.apache.ignite.configuration.*; +import org.apache.ignite.examples8.datagrid.store.model.*; +import org.apache.ignite.transactions.*; + +import java.util.*; + +import static org.apache.ignite.examples8.datagrid.store.CacheNodeWithStoreStartup.*; + +/** + * Demonstrates usage of cache with underlying persistent store configured. + * <p> + * Remote nodes should always be started using {@link CacheNodeWithStoreStartup}. + * Also you can change type of underlying store modifying configuration in the + * {@link CacheNodeWithStoreStartup#configure()} method. + */ +public class CacheStoreExample { + /** 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 org.apache.ignite.IgniteException If example execution failed. + */ + public static void main(String[] args) throws IgniteException { + IgniteConfiguration cfg = CacheNodeWithStoreStartup.configure(); + + // To start ignite with desired configuration uncomment the appropriate line. + try (Ignite ignite = Ignition.start(cfg)) { + System.out.println(); + System.out.println(">>> Cache store example started."); + System.out.println(">>> Store: " + STORE); + + IgniteCache<Long, Person> cache = ignite.jcache(null); + + // Clean up caches on all nodes before run. + cache.clear(); + + try (Transaction tx = ignite.transactions().txStart()) { + Person val = cache.get(id); + + System.out.println("Read value: " + val); + + val = cache.getAndPut(id, 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)); + + // If example run with CacheJdbcPojoStore. + // Example of CacheJdbcPojoStore special features. + if (STORE.equals(AUTO)) { + System.out.println(">>> Example of CacheJdbcPojoStore special feature: load from DB with custom SQL."); + + cache.clear(); + + System.out.println("Cache size: " + cache.size()); + + // Load values from DB into store with custom SQL. + cache.loadCache(null, "java.lang.Long", "select * from PERSON where id = 2"); + + System.out.println("Cache size: " + cache.size()); + System.out.println("Person: " + cache.get(2L)); + } + } + } + + /** + * Creates person. + * + * @param id ID. + * @param firstName First name. + * @param lastName Last name. + * @return Newly created person. + */ + private static Person person(long id, String firstName, String lastName) { + return new Person(id, firstName, lastName); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreLoadDataExample.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreLoadDataExample.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreLoadDataExample.java new file mode 100644 index 0000000..3ac505a --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/CacheStoreLoadDataExample.java @@ -0,0 +1,66 @@ +/* + * 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.examples8.datagrid.store; + +import org.apache.ignite.*; +import org.apache.ignite.examples8.*; + +/** + * Loads data on all cache nodes from persistent store at cache startup by calling + * {@link org.apache.ignite.IgniteCache#loadCache(org.apache.ignite.lang.IgniteBiPredicate, Object...)} method. + * <p> + * Remote nodes should always be started using {@link CacheNodeWithStoreStartup}. + * Also you can change type of underlying store modifying configuration in the + * {@link CacheNodeWithStoreStartup#configure()} method. + */ +public class CacheStoreLoadDataExample { + /** 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; + + /** + * Executes example. + * + * @param args Command line arguments, none required. + * @throws org.apache.ignite.IgniteException If example execution failed. + */ + public static void main(String[] args) throws IgniteException { + ExamplesUtils.checkMinMemory(MIN_MEMORY); + + try (Ignite ignite = Ignition.start(CacheNodeWithStoreStartup.configure())) { + System.out.println(); + System.out.println(">>> Cache store load data example started."); + + final IgniteCache<String, Integer> cache = ignite.jcache(null); + + // Clean up caches on all nodes before run. + cache.clear(); + + 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."); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/CacheDummyPersonStore.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/CacheDummyPersonStore.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/CacheDummyPersonStore.java new file mode 100644 index 0000000..4d3f592 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/CacheDummyPersonStore.java @@ -0,0 +1,120 @@ +/* + * 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.examples8.datagrid.store.dummy; + +import org.apache.ignite.*; +import org.apache.ignite.cache.store.*; +import org.apache.ignite.examples8.datagrid.store.model.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.resources.*; +import org.apache.ignite.transactions.*; +import org.jetbrains.annotations.*; + +import java.util.*; +import java.util.concurrent.*; + +/** + * Dummy cache store implementation. + */ +public class CacheDummyPersonStore extends CacheStoreAdapter<Long, Person> { + /** Auto-inject ignite instance. */ + @IgniteInstanceResource + private Ignite ignite; + + /** Auto-inject cache name. */ + @CacheNameResource + private String cacheName; + + /** */ + @CacheStoreSessionResource + private CacheStoreSession ses; + + /** Dummy database. */ + private Map<Long, Person> dummyDB = new ConcurrentHashMap<>(); + + /** {@inheritDoc} */ + @Override public Person load(Long key) { + Transaction tx = transaction(); + + System.out.println(">>> Store load [key=" + key + ", xid=" + (tx == null ? null : tx.xid()) + ']'); + + return dummyDB.get(key); + } + + /** {@inheritDoc} */ + @Override public void write(javax.cache.Cache.Entry<? extends Long, ? extends Person> entry) { + Transaction tx = transaction(); + + Long key = entry.getKey(); + Person val = entry.getValue(); + + System.out.println(">>> Store put [key=" + key + ", val=" + val + ", xid=" + (tx == null ? null : tx.xid()) + ']'); + + dummyDB.put(key, val); + } + + /** {@inheritDoc} */ + @Override public void delete(Object key) { + Transaction tx = transaction(); + + System.out.println(">>> Store remove [key=" + key + ", xid=" + (tx == null ? null : tx.xid()) + ']'); + + dummyDB.remove(key); + } + + /** {@inheritDoc} */ + @Override public void loadCache(IgniteBiInClosure<Long, Person> clo, Object... args) { + int cnt = (Integer)args[0]; + + System.out.println(">>> Store loadCache for entry count: " + cnt); + + for (int i = 0; i < cnt; i++) { + // Generate dummy person on the fly. + Person p = new Person(i, "first-" + i, "last-" + 1); + + // Ignite will automatically discard entries that don't belong on this node, + // but we check if local node is primary or backup anyway just to demonstrate that we can. + // Ideally, partition ID of a key would be stored in the database and only keys + // for partitions that belong on this node would be loaded from database. + if (ignite.affinity(cacheName).isPrimaryOrBackup(ignite.cluster().localNode(), p.getId())) { + // Update dummy database. + // In real life data would be loaded from database. + dummyDB.put(p.getId(), p); + + // Pass data to cache. + clo.apply(p.getId(), p); + } + } + } + + /** + * @return Current transaction. + */ + @Nullable private Transaction transaction() { + CacheStoreSession ses = session(); + + return ses != null ? ses.transaction() : null; + } + + /** + * @return Store session. + */ + private CacheStoreSession session() { + return ses; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/package.html ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/package.html b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/package.html new file mode 100644 index 0000000..4e8f3f4 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/dummy/package.html @@ -0,0 +1,24 @@ +<!-- + 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. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> + <!-- Package description. --> + Contains dummy cache store implementation. +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/CacheHibernatePersonStore.java ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/CacheHibernatePersonStore.java b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/CacheHibernatePersonStore.java new file mode 100644 index 0000000..5a707ad --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/CacheHibernatePersonStore.java @@ -0,0 +1,290 @@ +/* + * 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.examples8.datagrid.store.hibernate; + +import org.apache.ignite.cache.store.*; +import org.apache.ignite.examples8.datagrid.store.model.*; +import org.apache.ignite.lang.*; +import org.apache.ignite.resources.*; +import org.apache.ignite.transactions.Transaction; +import org.hibernate.*; +import org.hibernate.cfg.*; +import org.jetbrains.annotations.*; + +import javax.cache.integration.*; +import java.util.*; + +/** + * Example of {@link org.apache.ignite.cache.store.CacheStore} implementation that uses Hibernate + * and deals with maps {@link java.util.UUID} to {@link org.apache.ignite.examples8.datagrid.store.model.Person}. + */ +public class CacheHibernatePersonStore extends CacheStoreAdapter<Long, Person> { + /** Default hibernate configuration resource path. */ + private static final String DFLT_HIBERNATE_CFG = "/org/apache/ignite/examples/datagrid/store/hibernate/hibernate.cfg.xml"; + + /** Session attribute name. */ + private static final String ATTR_SES = "HIBERNATE_STORE_SESSION"; + + /** Session factory. */ + private SessionFactory sesFactory; + + /** Auto-injected store session. */ + @CacheStoreSessionResource + private CacheStoreSession ses; + + /** + * Default constructor. + */ + public CacheHibernatePersonStore() { + sesFactory = new Configuration().configure(DFLT_HIBERNATE_CFG).buildSessionFactory(); + } + + /** {@inheritDoc} */ + @Override public Person load(Long key) { + Transaction tx = transaction(); + + System.out.println(">>> Store load [key=" + key + ", xid=" + (tx == null ? null : tx.xid()) + ']'); + + Session ses = session(tx); + + try { + return (Person) ses.get(Person.class, key); + } + catch (HibernateException e) { + rollback(ses, tx); + + throw new CacheLoaderException("Failed to load value from cache store with key: " + key, e); + } + finally { + end(ses, tx); + } + } + + /** {@inheritDoc} */ + @Override public void write(javax.cache.Cache.Entry<? extends Long, ? extends Person> entry) { + Transaction tx = transaction(); + + Long key = entry.getKey(); + + Person val = entry.getValue(); + + System.out.println(">>> Store put [key=" + key + ", val=" + val + ", xid=" + (tx == null ? null : tx.xid()) + ']'); + + if (val == null) { + delete(key); + + return; + } + + Session ses = session(tx); + + try { + ses.saveOrUpdate(val); + } + catch (HibernateException e) { + rollback(ses, tx); + + throw new CacheWriterException("Failed to put value to cache store [key=" + key + ", val" + val + "]", e); + } + finally { + end(ses, tx); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings({"JpaQueryApiInspection"}) + @Override public void delete(Object key) { + Transaction tx = transaction(); + + System.out.println(">>> Store remove [key=" + key + ", xid=" + (tx == null ? null : tx.xid()) + ']'); + + Session ses = session(tx); + + try { + ses.createQuery("delete " + Person.class.getSimpleName() + " where key = :key") + .setParameter("key", key).setFlushMode(FlushMode.ALWAYS).executeUpdate(); + } + catch (HibernateException e) { + rollback(ses, tx); + + throw new CacheWriterException("Failed to remove value from cache store with key: " + key, e); + } + finally { + end(ses, tx); + } + } + + /** {@inheritDoc} */ + @Override public void loadCache(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."); + + final int entryCnt = (Integer)args[0]; + + Session ses = session(null); + + try { + int cnt = 0; + + List res = ses.createCriteria(Person.class).list(); + + if (res != null) { + Iterator iter = res.iterator(); + + while (cnt < entryCnt && iter.hasNext()) { + Person person = (Person)iter.next(); + + clo.apply(person.getId(), person); + + cnt++; + } + } + + System.out.println(">>> Loaded " + cnt + " values into cache."); + } + catch (HibernateException e) { + throw new CacheLoaderException("Failed to load values from cache store.", e); + } + finally { + end(ses, null); + } + } + + /** + * Rolls back hibernate session. + * + * @param ses Hibernate session. + * @param tx Cache ongoing transaction. + */ + private void rollback(Session ses, Transaction tx) { + // Rollback only if there is no cache transaction, + // otherwise txEnd() will do all required work. + if (tx == null) { + org.hibernate.Transaction hTx = ses.getTransaction(); + + if (hTx != null && hTx.isActive()) + hTx.rollback(); + } + } + + /** + * Ends hibernate session. + * + * @param ses Hibernate session. + * @param tx Cache ongoing transaction. + */ + private void end(Session ses, @Nullable Transaction tx) { + // Commit only if there is no cache transaction, + // otherwise txEnd() will do all required work. + if (tx == null) { + org.hibernate.Transaction hTx = ses.getTransaction(); + + if (hTx != null && hTx.isActive()) + hTx.commit(); + + ses.close(); + } + } + + /** {@inheritDoc} */ + @Override public void txEnd(boolean commit) { + CacheStoreSession storeSes = session(); + + Transaction tx = storeSes.transaction(); + + Map<String, Session> props = storeSes.properties(); + + Session ses = props.remove(ATTR_SES); + + if (ses != null) { + org.hibernate.Transaction hTx = ses.getTransaction(); + + if (hTx != null) { + try { + if (commit) { + ses.flush(); + + hTx.commit(); + } + else + hTx.rollback(); + + System.out.println("Transaction ended [xid=" + tx.xid() + ", commit=" + commit + ']'); + } + catch (HibernateException e) { + throw new CacheWriterException("Failed to end transaction [xid=" + tx.xid() + + ", commit=" + commit + ']', e); + } + finally { + ses.close(); + } + } + } + } + + /** + * Gets Hibernate session. + * + * @param tx Cache transaction. + * @return Session. + */ + private Session session(@Nullable Transaction tx) { + Session ses; + + if (tx != null) { + Map<String, Session> props = session().properties(); + + ses = props.get(ATTR_SES); + + if (ses == null) { + ses = sesFactory.openSession(); + + ses.beginTransaction(); + + // Store session in session properties, so it can be accessed + // for other operations on the same transaction. + props.put(ATTR_SES, ses); + + System.out.println("Hibernate session open [ses=" + ses + ", tx=" + tx.xid() + "]"); + } + } + else { + ses = sesFactory.openSession(); + + ses.beginTransaction(); + } + + return ses; + } + + /** + * @return Current transaction. + */ + @Nullable private Transaction transaction() { + CacheStoreSession ses = session(); + + return ses != null ? ses.transaction() : null; + } + + /** + * @return Store session. + */ + private CacheStoreSession session() { + return ses; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/Person.hbm.xml ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/Person.hbm.xml b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/Person.hbm.xml new file mode 100644 index 0000000..1aac4e4 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/Person.hbm.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + 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. +--> + + +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> + +<hibernate-mapping default-access="field"> + <class name="org.apache.ignite.examples8.datagrid.store.model.Person" table="PERSONS"> + <!-- ID. --> + <id name="id"/> + + <!-- We only map data we are interested in. --> + <property name="firstName"/> + <property name="lastName"/> + </class> +</hibernate-mapping> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/hibernate.cfg.xml ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/hibernate.cfg.xml b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/hibernate.cfg.xml new file mode 100644 index 0000000..80a43e7 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/hibernate.cfg.xml @@ -0,0 +1,41 @@ +<?xml version='1.0' encoding='utf-8'?> + +<!-- + 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. +--> + +<!DOCTYPE hibernate-configuration PUBLIC + "-//Hibernate/Hibernate Configuration DTD 3.0//EN" + "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> + +<!-- + Hibernate configuration. +--> +<hibernate-configuration> + <session-factory> + <!-- Database connection settings (private in-memory database). --> + <property name="connection.url">jdbc:h2:mem:example;DB_CLOSE_DELAY=-1</property> + + <!-- Only validate the database schema on startup in production mode. --> + <property name="hbm2ddl.auto">update</property> + + <!-- Do not output SQL. --> + <property name="show_sql">false</property> + + <!-- Mappings. --> + <mapping resource="org/apache/ignite/examples/datagrid/store/hibernate/Person.hbm.xml"/> + </session-factory> +</hibernate-configuration> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/28720c44/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/package.html ---------------------------------------------------------------------- diff --git a/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/package.html b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/package.html new file mode 100644 index 0000000..96ae123 --- /dev/null +++ b/examples/src/main/java8/org/apache/ignite/examples8/datagrid/store/hibernate/package.html @@ -0,0 +1,24 @@ +<!-- + 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. +--> + +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<body> + <!-- Package description. --> + Contains Hibernate-based cache store implementation. +</body> +</html>