http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheAsyncApiExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheAsyncApiExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheAsyncApiExample.scala new file mode 100644 index 0000000..1059c5b --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheAsyncApiExample.scala @@ -0,0 +1,75 @@ +/* + * + * * 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.scalar.examples.datagrid + +import org.apache.ignite.examples.ExampleNodeStartup +import org.apache.ignite.internal.util.scala.impl +import org.apache.ignite.lang.{IgniteFuture, IgniteInClosure} +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +/** + * This example demonstrates some of the cache rich API capabilities. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheAsyncApiExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheAsyncApiExample.getClass.getSimpleName + + scalar(CONFIG) { + println() + println(">>> Cache asynchronous API example started.") + + val cache = createCache$[Integer, String](CACHE_NAME) + + try { + // Enable asynchronous mode. + val asyncCache = cache.withAsync() + + // Execute several puts asynchronously. + val t = (0 until 10).map(i => { + asyncCache.put(i, String.valueOf(i)) + + asyncCache.future().asInstanceOf[IgniteFuture[_]] + }).foreach(_.get()) + + // Execute get operation asynchronously. + asyncCache.get(1) + + // Asynchronously wait for result. + asyncCache.future[String].listen(new IgniteInClosure[IgniteFuture[String]] { + @impl def apply(fut: IgniteFuture[String]) { + println("Get operation completed [value=" + fut.get + ']') + } + }) + } + finally { + cache.close() + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheContinuousQueryExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheContinuousQueryExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheContinuousQueryExample.scala new file mode 100644 index 0000000..637c13c --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheContinuousQueryExample.scala @@ -0,0 +1,108 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package org.apache.ignite.scalar.examples.datagrid + +import org.apache.ignite.IgniteDataStreamer +import org.apache.ignite.cache.CacheEntryEventSerializableFilter +import org.apache.ignite.cache.query.{ContinuousQuery, ScanQuery} +import org.apache.ignite.examples.ExampleNodeStartup +import org.apache.ignite.internal.util.scala.impl +import org.apache.ignite.lang.IgniteBiPredicate +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import javax.cache.event.{CacheEntryEvent, CacheEntryUpdatedListener} +import java.lang.{Iterable => JavaIterable} + +import scala.collection.JavaConversions._ + +/** + * Demonstrates how cache can be populated with data utilizing [[IgniteDataStreamer]] API. + * [[IgniteDataStreamer]] is a lot more efficient to use than standard + * `put(...)` operation as it properly buffers cache requests + * together and properly manages load on remote nodes. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheContinuousQueryExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheContinuousQueryExample.getClass.getSimpleName + + scalar(CONFIG) { + println() + println(">>> Cache continuous query example started.") + + val cache = createCache$[Integer, String](CACHE_NAME) + + try { + val keyCnt = 20 + + for (i <- 0 until keyCnt) + cache.put(i, Integer.toString(i)) + + val qry = new ContinuousQuery[Integer, String] + + qry.setInitialQuery(new ScanQuery[Integer, String](new IgniteBiPredicate[Integer, String] { + @impl def apply(key: Integer, value: String): Boolean = { + key > 10 + } + })) + + qry.setLocalListener(new CacheEntryUpdatedListener[Integer, String] { + @impl def onUpdated(events: JavaIterable[CacheEntryEvent[_ <: Integer, _ <: String]]) { + for (e <- events) + println("Updated entry [key=" + e.getKey + ", val=" + e.getValue + ']') + } + }) + + qry.setRemoteFilter(new CacheEntryEventSerializableFilter[Integer, String] { + @impl def evaluate(e: CacheEntryEvent[_ <: Integer, _ <: String]): Boolean = { + e.getKey > 10 + } + }) + + val cur = cache.query(qry) + + try { + for (e <- cur) + println("Queried existing entry [key=" + e.getKey + ", val=" + e.getValue + ']') + + for (i <- keyCnt until (keyCnt + 10)) + cache.put(i, Integer.toString(i)) + + Thread.sleep(2000) + } + finally { + if (cur != null) + cur.close() + } + } + finally { + cache.close() + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheDataStreamerExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheDataStreamerExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheDataStreamerExample.scala new file mode 100644 index 0000000..b6bac1b --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheDataStreamerExample.scala @@ -0,0 +1,88 @@ +/* + * + * * 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.scalar.examples.datagrid + +import org.apache.ignite.IgniteDataStreamer +import org.apache.ignite.examples.{ExampleNodeStartup, ExamplesUtils} +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +/** + * Demonstrates how cache can be populated with data utilizing [[IgniteDataStreamer]] API. + * [[IgniteDataStreamer]] is a lot more efficient to use than standard + * `put(...)` operation as it properly buffers cache requests + * together and properly manages load on remote nodes. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheDataStreamerExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheDataStreamerExample.getClass.getSimpleName + + /** Number of entries to load. */ + private val ENTRY_COUNT = 500000 + + /** Heap size required to run this example. */ + val MIN_MEMORY = 512 * 1024 * 1024 + + ExamplesUtils.checkMinMemory(MIN_MEMORY) + + scalar(CONFIG) { + println() + println(">>> Cache data streamer example started.") + + val cache = createCache$(CACHE_NAME) + + try { + val start = System.currentTimeMillis + + val stmr = dataStreamer$[Integer, String](CACHE_NAME) + + try { + stmr.perNodeBufferSize(1024) + stmr.perNodeParallelOperations(8) + + for (i <- 0 until ENTRY_COUNT) { + stmr.addData(i, Integer.toString(i)) + + if (i > 0 && i % 10000 == 0) + println("Loaded " + i + " keys.") + } + } + finally { + stmr.close() + } + + val end = System.currentTimeMillis + + println(">>> Loaded " + ENTRY_COUNT + " keys in " + (end - start) + "ms.") + } + finally { + cache.close() + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheEventsExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheEventsExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheEventsExample.scala new file mode 100644 index 0000000..cd93776 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheEventsExample.scala @@ -0,0 +1,89 @@ +/* + * + * * 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.scalar.examples.datagrid + +import org.apache.ignite.events.CacheEvent +import org.apache.ignite.events.EventType._ +import org.apache.ignite.examples.ExampleNodeStartup +import org.apache.ignite.internal.util.scala.impl +import org.apache.ignite.lang.{IgniteBiPredicate, IgnitePredicate} +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import java.util.UUID + +/** + * This examples demonstrates events API. Note that ignite events are disabled by default and + * must be specifically enabled, just like in `examples/config/example-ignite.xml` file. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheEventsExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheEventsExample.getClass.getSimpleName + + scalar(CONFIG) { + println() + println(">>> Cache events example started.") + + val cache = createCache$[Integer, String](CACHE_NAME) + + val cluster = cluster$ + + try { + val locLsnr = new IgniteBiPredicate[UUID, CacheEvent] { + @impl def apply(uuid: UUID, evt: CacheEvent): Boolean = { + println("Received event [evt=" + evt.name + ", key=" + evt.key + + ", oldVal=" + evt.oldValue + ", newVal=" + evt.newValue) + + true + } + } + + val rmtLsnr = new IgnitePredicate[CacheEvent] { + @impl def apply(evt: CacheEvent): Boolean = { + println("Cache event [name=" + evt.name + ", key=" + evt.key + ']') + + val key = evt.key.asInstanceOf[Int] + + key >= 10 && ignite$.affinity(CACHE_NAME).isPrimary(cluster.localNode, key) + } + } + + ignite$.events(cluster.forCacheNodes(CACHE_NAME)).remoteListen(locLsnr, rmtLsnr, + EVT_CACHE_OBJECT_PUT, EVT_CACHE_OBJECT_READ, EVT_CACHE_OBJECT_REMOVED) + + for (i <- 0 until 20) + cache.put(i, Integer.toString(i)) + + Thread.sleep(2000) + } + finally { + if (cache != null) cache.close() + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCachePutGetExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCachePutGetExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCachePutGetExample.scala new file mode 100644 index 0000000..bf1c375 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCachePutGetExample.scala @@ -0,0 +1,106 @@ +/* + * + * * 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.scalar.examples.datagrid + +import org.apache.ignite.examples.ExampleNodeStartup +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ +import org.apache.ignite.{IgniteCache, IgniteException} + +import java.util.{HashMap => JavaMap} + +import scala.collection.JavaConversions._ + +/** + * This example demonstrates very basic operations on cache, such as 'put' and 'get'. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCachePutGetExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCachePutGetExample.getClass.getSimpleName + + scalar(CONFIG) { + val cache = createCache$[Integer, String](CACHE_NAME) + + try { + putGet(cache) + putAllGetAll(cache) + } + finally { + if (cache != null) cache.close() + } + } + + /** + * Execute individual puts and gets. + * + * @throws IgniteException If failed. + */ + @throws(classOf[IgniteException]) + private def putGet(cache: IgniteCache[Integer, String]) { + println() + println(">>> Cache put-get example started.") + + val keyCnt = 20 + + for (i <- 0 until keyCnt) + cache.put(i, Integer.toString(i)) + + println(">>> Stored values in cache.") + + for (i <- 0 until keyCnt) + println("Got [key=" + i + ", val=" + cache.get(i) + ']') + } + + /** + * Execute bulk `putAll(...)` and `getAll(...)` operations. + * + * @throws IgniteException If failed. + */ + @throws(classOf[IgniteException]) + private def putAllGetAll(cache: IgniteCache[Integer, String]) { + println() + println(">>> Starting putAll-getAll example.") + + val keyCnt = 20 + + val batch = new JavaMap[Integer, String] + + for (i <- 0 until keyCnt) + batch.put(i, "bulk-" + Integer.toString(i)) + + cache.putAll(batch) + + println(">>> Bulk-stored values in cache.") + + val vals = cache.getAll(batch.keySet) + + for (e <- vals.entrySet) + println("Got entry [key=" + e.getKey + ", val=" + e.getValue + ']') + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheQueryExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheQueryExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheQueryExample.scala new file mode 100644 index 0000000..1876515 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheQueryExample.scala @@ -0,0 +1,305 @@ +/* + * + * * 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.scalar.examples.datagrid + +import org.apache.ignite.IgniteCache +import org.apache.ignite.cache.CacheMode._ +import org.apache.ignite.cache.affinity.AffinityKey +import org.apache.ignite.cache.query._ +import org.apache.ignite.internal.util.scala.impl +import org.apache.ignite.lang.IgniteBiPredicate +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import javax.cache.Cache +import java.lang.{Iterable => JavaIterable} +import java.util.UUID + +import scala.collection.JavaConversions._ + +/** + * Demonstrates cache ad-hoc queries with Scalar. + * <p/> + * Remote nodes should be started using `ExampleNodeStartup` which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheQueryExample { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Organizations cache name. */ + private val ORG_CACHE = ScalarCacheQueryExample.getClass.getSimpleName + "Organizations" + + /** Persons cache name. */ + private val PERSON_CACHE = ScalarCacheQueryExample.getClass.getSimpleName + "Persons" + + /** + * Example entry point. No arguments required. + * + * @param args Command line arguments. None required. + */ + def main(args: Array[String]) { + scalar(CONFIG) { + val orgCache = createCache$(ORG_CACHE, PARTITIONED, Seq(classOf[UUID], classOf[Organization])) + + try { + val personCache = createCache$(PERSON_CACHE, PARTITIONED, Seq(classOf[AffinityKey[_]], classOf[Person])) + + try { + initialize() + + scanQuery() + + sqlQuery() + + sqlQueryWithJoin() + + textQuery() + + sqlQueryWithAggregation() + + sqlFieldsQuery() + + sqlFieldsQueryWithJoin() + + print("Cache query example finished.") + } + finally { + if (personCache != null) + personCache.close() + } + } + finally { + if (orgCache != null) + orgCache.close() + } + } + } + + /** + * Gets instance of typed cache view to use. + * + * @return Cache to use. + */ + private def mkCache[K, V](cacheName: String): IgniteCache[K, V] = cache$[K, V](cacheName).get + + /** + * Example for scan query based on a predicate. + */ + private def scanQuery() { + val cache = mkCache[AffinityKey[UUID], Person](PERSON_CACHE) + + val scan = new ScanQuery[AffinityKey[UUID], Person]( + new IgniteBiPredicate[AffinityKey[UUID], Person] { + @impl def apply(key: AffinityKey[UUID], person: Person): Boolean = { + person.salary <= 1000 + } + }) + + print("People with salaries between 0 and 1000 (queried with SCAN query): ", cache.query(scan).getAll) + } + + /** + * Example for SQL queries based on salary ranges. + */ + private def sqlQuery() { + val cache = mkCache[AffinityKey[UUID], Person](PERSON_CACHE) + + val sql = "salary > ? and salary <= ?" + + print("People with salaries between 0 and 1000 (queried with SQL query): ", + cache.query(new SqlQuery[AffinityKey[UUID], Person](classOf[Person], sql) + .setArgs(0.asInstanceOf[Object], 1000.asInstanceOf[Object])).getAll) + + print("People with salaries between 1000 and 2000 (queried with SQL query): ", + cache.query(new SqlQuery[AffinityKey[UUID], Person](classOf[Person], sql) + .setArgs(1000.asInstanceOf[Object], 2000.asInstanceOf[Object])).getAll) + } + + /** + * Example for SQL queries based on all employees working for a specific organization. + */ + private def sqlQueryWithJoin() { + val cache = mkCache[AffinityKey[UUID], Person](PERSON_CACHE) + + val joinSql = "from Person, \"" + ORG_CACHE + "\".Organization as org " + + "where Person.orgId = org.id " + + "and lower(org.name) = lower(?)" + + print("Following people are 'ApacheIgnite' employees: ", + cache.query(new SqlQuery[AffinityKey[UUID], Person](classOf[Person], joinSql).setArgs("ApacheIgnite")).getAll) + print("Following people are 'Other' employees: ", + cache.query(new SqlQuery[AffinityKey[UUID], Person](classOf[Person], joinSql).setArgs("Other")).getAll) + } + + /** + * Example for TEXT queries using LUCENE-based indexing of people's resumes. + */ + private def textQuery() { + val cache = mkCache[AffinityKey[UUID], Person](PERSON_CACHE) + + val masters: QueryCursor[Cache.Entry[AffinityKey[UUID], Person]] = + cache.query(new TextQuery[AffinityKey[UUID], Person](classOf[Person], "Master")) + + val bachelors: QueryCursor[Cache.Entry[AffinityKey[UUID], Person]] = + cache.query(new TextQuery[AffinityKey[UUID], Person](classOf[Person], "Bachelor")) + + print("Following people have 'Master Degree' in their resumes: ", masters.getAll) + + print("Following people have 'Bachelor Degree' in their resumes: ", bachelors.getAll) + } + + /** + * Example for SQL queries to calculate average salary for a specific organization. + */ + private def sqlQueryWithAggregation() { + val cache = mkCache[AffinityKey[UUID], Person](PERSON_CACHE) + + val sql = "select avg(salary) " + + "from Person, \"" + ORG_CACHE + "\".Organization as org " + + "where Person.orgId = org.id " + + "and lower(org.name) = lower(?)" + + val cursor = cache.query(new SqlFieldsQuery(sql).setArgs("ApacheIgnite")) + + print("Average salary for 'ApacheIgnite' employees: ", cursor.getAll) + } + + /** + * Example for SQL-based fields queries that return only required + * fields instead of whole key-value pairs. + */ + private def sqlFieldsQuery() { + val cache = ignite$.cache[AffinityKey[UUID], Person](PERSON_CACHE) + + // Execute query to get names of all employees. + val cursor = cache.query(new SqlFieldsQuery("select concat(firstName, ' ', lastName) from Person")) + + val res = cursor.getAll + + print("Names of all employees:", res) + } + + /** + * Example for SQL-based fields queries that return only required + * fields instead of whole key-value pairs. + */ + private def sqlFieldsQueryWithJoin() { + val cache = ignite$.cache[AffinityKey[UUID], Person](PERSON_CACHE) + + val sql = "select concat(firstName, ' ', lastName), org.name " + "from Person, \"" + + ORG_CACHE + "\".Organization as org " + "where Person.orgId = org.id" + + val cursor = cache.query(new SqlFieldsQuery(sql)) + + val res = cursor.getAll + + print("Names of all employees and organizations they belong to:", res) + } + + /** + * Populate cache with test data. + */ + private def initialize() { + val orgCache = mkCache[UUID, Organization](ORG_CACHE) + + val org1 = new Organization("ApacheIgnite") + val org2 = new Organization("Other") + + orgCache += (org1.id -> org1) + orgCache += (org2.id -> org2) + + val personCache = mkCache[AffinityKey[UUID], Person](PERSON_CACHE) + + val p1 = new Person(org1, "John", "Doe", 2000, "John Doe has Master Degree.") + val p2 = new Person(org1, "Jane", "Doe", 1000, "Jane Doe has Bachelor Degree.") + val p3 = new Person(org2, "John", "Smith", 1000, "John Smith has Bachelor Degree.") + val p4 = new Person(org2, "Jane", "Smith", 2000, "Jane Smith has Master Degree.") + + personCache += (p1.key -> p1) + personCache += (p2.key -> p2) + personCache += (p3.key -> p3) + personCache += (p4.key -> p4) + } + + /** + * Prints message. + * + * @param msg Message to print before all objects are printed. + */ + private def print(msg: String) { + assert(msg != null) + + println() + println(">>> " + msg) + } + + /** + * Prints object or collection of objects to standard out. + * + * @param msg Message to print before object is printed. + * @param res Collection of result object to print. + */ + private def print(msg: String, res: JavaIterable[_]) { + assert(msg != null) + assert(res != null) + + print(msg) + + res.foreach(e => println(">>> " + e.toString)) + } + + /** + * Organization class. + */ + private case class Organization( + @ScalarCacheQuerySqlField + name: String) { + /** Organization ID. */ + @ScalarCacheQuerySqlField + val id = UUID.randomUUID + } + + /** + * Person class. + */ + private case class Person(org: Organization, + @ScalarCacheQuerySqlField firstName: String, + @ScalarCacheQuerySqlField lastName: String, + @ScalarCacheQuerySqlField salary: Double, + @ScalarCacheQueryTextField resume: String) { + /** Person ID. */ + val id = UUID.randomUUID + + /** Organization ID. */ + @ScalarCacheQuerySqlField + val orgId = org.id + + /** Affinity key for this person. */ + val key = new AffinityKey[UUID](id, org.id) + + /** + * `toString` implementation. + */ + override def toString: String = { + firstName + " " + lastName + " [salary: " + salary + ", resume: " + resume + "]" + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheTransactionExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheTransactionExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheTransactionExample.scala new file mode 100644 index 0000000..a9c0b4c --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/ScalarCacheTransactionExample.scala @@ -0,0 +1,127 @@ +/* + * + * * 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.scalar.examples.datagrid + +import org.apache.ignite.cache.CacheAtomicityMode +import org.apache.ignite.examples.ExampleNodeStartup +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ +import org.apache.ignite.transactions.TransactionConcurrency._ +import org.apache.ignite.transactions.TransactionIsolation._ +import org.apache.ignite.{IgniteCache, IgniteException} + +import java.io.Serializable + +/** + * Demonstrates how to use cache transactions. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheTransactionExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheTransactionExample.getClass.getSimpleName + + scalar(CONFIG) { + println() + println(">>> Cache transaction example started.") + + val cache = createCache$[Integer, Account](CACHE_NAME, atomicityMode = CacheAtomicityMode.TRANSACTIONAL) + + try { + cache.put(1, new Account(1, 100)) + cache.put(2, new Account(1, 200)) + + println() + println(">>> Accounts before deposit: ") + println(">>> " + cache.get(1)) + println(">>> " + cache.get(2)) + + deposit(cache, 1, 100) + deposit(cache, 2, 200) + + println() + println(">>> Accounts after transfer: ") + println(">>> " + cache.get(1)) + println(">>> " + cache.get(2)) + println(">>> Cache transaction example finished.") + } + finally { + cache.close() + } + } + + /** + * Make deposit into specified account. + * + * @param acctId Account ID. + * @param amount Amount to deposit. + * @throws IgniteException If failed. + */ + @throws(classOf[IgniteException]) + private def deposit(cache: IgniteCache[Integer, Account], acctId: Int, amount: Double) { + val tx = transaction$(PESSIMISTIC, REPEATABLE_READ) + + try { + val acct = cache.get(acctId) + + assert(acct != null) + + acct.update(amount) + + cache.put(acctId, acct) + + tx.commit() + } + finally { + tx.close() + } + + println() + println(">>> Transferred amount: $" + amount) + } + + /** + * Account. + * + * @param id Account ID. + * @param balance Balance. + */ + private class Account(id: Int, var balance: Double) extends Serializable { + /** + * Change balance by specified amount. + * + * @param amount Amount to add to balance (may be negative). + */ + private[datagrid] def update(amount: Double) { + balance += amount + } + + override def toString: String = { + "Account [id=" + id + ", balance=$" + balance + ']' + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/Post.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/Post.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/Post.scala new file mode 100644 index 0000000..ee44eb4 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/Post.scala @@ -0,0 +1,115 @@ +/* + * + * * 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.scalar.examples.datagrid.hibernate + +import javax.persistence._ +import java.util.Date + +/** + * An entity class representing a post, that a + * [[User]] has made on some public service. + */ +@Entity class Post { + /** ID. */ + @Id @GeneratedValue(strategy = GenerationType.AUTO) private var id = 0L + + /** Author. */ + @ManyToOne private var author: User = null + + /** Text. */ + private var text: String = null + + /** Created timestamp. */ + private var created: Date = null + + /** + * Constructor. + * + * @param author Author. + * @param text Text. + */ + private[hibernate] def this(author: User, text: String) { + this() + + this.author = author + this.text = text + created = new Date + } + + /** + * @return ID. + */ + def getId: Long = { + id + } + + /** + * @param id New ID. + */ + def setId(id: Long) { + this.id = id + } + + /** + * @return Author. + */ + def getAuthor: User = { + author + } + + /** + * @param author New author. + */ + def setAuthor(author: User) { + this.author = author + } + + /** + * @return Text. + */ + def getText: String = { + text + } + + /** + * @param text New text. + */ + def setText(text: String) { + this.text = text + } + + /** + * @return Created timestamp. + */ + def getCreated: Date = { + created.clone.asInstanceOf[Date] + } + + /** + * @param created New created timestamp. + */ + def setCreated(created: Date) { + this.created = created.clone.asInstanceOf[Date] + } + + override def toString: String = { + "Post [id=" + id + ", text=" + text + ", created=" + created + ']' + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/ScalarHibernateL2CacheExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/ScalarHibernateL2CacheExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/ScalarHibernateL2CacheExample.scala new file mode 100644 index 0000000..05e5def --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/ScalarHibernateL2CacheExample.scala @@ -0,0 +1,242 @@ +/* + * + * * 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.scalar.examples.datagrid.hibernate + +import org.apache.ignite.IgniteCache +import org.apache.ignite.cache.CacheAtomicityMode +import org.apache.ignite.cache.CacheAtomicityMode._ +import org.apache.ignite.cache.CacheWriteSynchronizationMode._ +import org.apache.ignite.configuration.CacheConfiguration +import org.apache.ignite.examples.{ExampleNodeStartup, ExamplesUtils} +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import org.hibernate.cfg.Configuration +import org.hibernate.service.ServiceRegistryBuilder +import org.hibernate.{Session, SessionFactory} + +import javax.persistence._ +import java.net.URL +import java.util.{Arrays, HashSet => JavaHashSet, List => JavaList, Set => JavaSet} + +import scala.collection.JavaConversions._ + +/** + * 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: [[User]] and [[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 [[AccessType#READ_ONLY]] L2 cache access type, but you + * can experiment with other access types by modifying the Hibernate configuration file + * `IGNITE_HOME/examples/config/hibernate/example-hibernate-L2-cache.xml`, used by the example. + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarHibernateL2CacheExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** JDBC URL for backing database (an H2 in-memory database is used). */ + private val JDBC_URL = "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1" + + /** Path to hibernate configuration file (will be resolved from application `CLASSPATH`). */ + private val HIBERNATE_CFG = "hibernate/example-scalar-hibernate-L2-cache.xml" + + /** Entity names for stats output. */ + private val ENTITY_NAMES: JavaList[String] = + Arrays.asList(classOf[User].getName, classOf[Post].getName, classOf[User].getName + ".posts") + // 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). + + scalar(CONFIG) { + println() + println(">>> Hibernate L2 cache example started.") + + val c1 = createCache("org.hibernate.cache.spi.UpdateTimestampsCache", ATOMIC) + val c2 = createCache("org.hibernate.cache.internal.StandardQueryCache", ATOMIC) + val c3 = createCache("org.apache.ignite.scalar.examples.datagrid.hibernate.User", TRANSACTIONAL) + val c4 = createCache("org.apache.ignite.scalar.examples.datagrid.hibernate.User.posts", TRANSACTIONAL) + val c5 = createCache("org.apache.ignite.scalar.examples.datagrid.hibernate.Post", TRANSACTIONAL) + + try { + val hibernateCfg: URL = ExamplesUtils.url(HIBERNATE_CFG) + + val sesFactory: SessionFactory = createHibernateSessionFactory(hibernateCfg) + + println() + println(">>> Creating objects.") + + var userId = 0L + + var ses: Session = sesFactory.openSession + + try { + val tx = ses.beginTransaction + + val user = new User("jedi", "Luke", "Skywalker") + + user.getPosts.add(new Post(user, "Let the Force be with you.")) + + ses.save(user) + + tx.commit() + + userId = user.getId + } + finally { + ses.close + } + + printStats(sesFactory) + + println() + println(">>> Querying object by ID.") + + for (i <- 0 until 3) { + ses = sesFactory.openSession + + try { + val tx = ses.beginTransaction + + val user = ses.get(classOf[User], userId).asInstanceOf[User] + + println("User: " + user) + + for (post <- user.getPosts) + println("\tPost: " + post) + + tx.commit() + } + finally { + ses.close + } + } + + printStats(sesFactory) + } + finally { + if (c1 != null) + c1.close() + + if (c2 != null) + c2.close() + + if (c3 != null) + c3.close() + + if (c4 != null) + c4.close() + + if (c5 != null) + c5.close() + } + } + + /** + * Creates cache. + * + * @param name Cache name. + * @param atomicityMode Atomicity mode. + * @return Cache configuration. + */ + private def createCache(name: String, atomicityMode: CacheAtomicityMode): IgniteCache[_, _] = { + val ccfg = new CacheConfiguration[AnyRef, AnyRef](name) + + ccfg.setAtomicityMode(atomicityMode) + + ccfg.setWriteSynchronizationMode(FULL_SYNC) + + createCache$(ccfg) + } + + /** + * Creates a new Hibernate [[SessionFactory]] using a programmatic + * configuration. + * + * @param hibernateCfg Hibernate configuration file. + * @return New Hibernate { @link SessionFactory}. + */ + private def createHibernateSessionFactory(hibernateCfg: URL): SessionFactory = { + val builder = new ServiceRegistryBuilder + + builder.applySetting("hibernate.connection.url", JDBC_URL) + + builder.applySetting("hibernate.show_sql", true) + + new Configuration().configure(hibernateCfg).buildSessionFactory(builder.buildServiceRegistry) + } + + /** + * Prints Hibernate L2 cache statistics to standard output. + * + * @param sesFactory Hibernate { @link SessionFactory}, for which to print + * statistics. + */ + private def printStats(sesFactory: SessionFactory) { + println("=== Hibernate L2 cache statistics ===") + + for (entityName <- ENTITY_NAMES) { + println("\tEntity: " + entityName) + + val stats = sesFactory.getStatistics.getSecondLevelCacheStatistics(entityName) + + println("\t\tL2 cache entries: " + stats.getEntries) + println("\t\tHits: " + stats.getHitCount) + println("\t\tMisses: " + stats.getMissCount) + } + + println("=====================================") + } +} + + + + http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/User.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/User.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/User.scala new file mode 100644 index 0000000..dccc1c5 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/hibernate/User.scala @@ -0,0 +1,136 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. See the NOTICE file distributed with + * * this work for additional information regarding copyright ownership. + * * The ASF licenses this file to You under the Apache License, Version 2.0 + * * (the "License"); you may not use this file except in compliance with + * * the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package org.apache.ignite.scalar.examples.datagrid.hibernate + +import org.hibernate.annotations.NaturalId + +import javax.persistence._ +import java.util.{HashSet => JavaHashSet, Set => JavaSet} + +/** + * 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 private[hibernate] class User { + /** ID. */ + @Id @GeneratedValue(strategy = GenerationType.AUTO) private var id = 0L + + /** Login. */ + @NaturalId private var login: String = null + + /** First name. */ + private var firstName: String = null + + /** Last name. */ + private var lastName: String = null + + /** Posts. */ + @OneToMany(mappedBy = "author", cascade = Array(CascadeType.ALL)) + private var posts: JavaSet[Post] = new JavaHashSet[Post] + + /** + * Constructor. + * + * @param login Login. + * @param firstName First name. + * @param lastName Last name. + */ + private[hibernate] def this(login: String, firstName: String, lastName: String) { + this() + this.login = login + this.firstName = firstName + this.lastName = lastName + } + + /** + * @return ID. + */ + def getId: Long = { + id + } + + /** + * @param id New ID. + */ + def setId(id: Long) { + this.id = id + } + + /** + * @return Login. + */ + def getLogin: String = { + login + } + + /** + * @param login New login. + */ + def setLogin(login: String) { + this.login = login + } + + /** + * @return First name. + */ + def getFirstName: String = { + firstName + } + + /** + * @param firstName New first name. + */ + def setFirstName(firstName: String) { + this.firstName = firstName + } + + /** + * @return Last name. + */ + def getLastName: String = { + lastName + } + + /** + * @param lastName New last name. + */ + def setLastName(lastName: String) { + this.lastName = lastName + } + + /** + * @return Posts. + */ + def getPosts: JavaSet[Post] = { + posts + } + + /** + * @param posts New posts. + */ + def setPosts(posts: JavaSet[Post]) { + this.posts = posts + } + + override def toString: String = { + "User [id=" + id + ", login=" + login + ", firstName=" + firstName + ", lastName=" + lastName + ']' + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/starschema/ScalarStarSchemaExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/starschema/ScalarStarSchemaExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/starschema/ScalarStarSchemaExample.scala new file mode 100644 index 0000000..870addf --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/starschema/ScalarStarSchemaExample.scala @@ -0,0 +1,314 @@ +/* + * 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.scalar.examples.datagrid.starschema + +import org.apache.ignite.IgniteCache +import org.apache.ignite.cache.CacheMode +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import org.jsr166.ThreadLocalRandom8 + +import javax.cache.Cache +import java.lang.{Integer => JavaInt} +import java.util.ConcurrentModificationException + +import scala.collection.JavaConversions._ + +/** + * <a href="http://en.wikipedia.org/wiki/Snowflake_schema">Snowflake Schema</a> is a logical + * arrangement of data in which data is split into `dimensions` and `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 + * `CacheMode#REPLICATED REPLICATED` caches and <i>facts</i> in much larger + * `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>, `DimProduct` and `DimStore` and + * one <i>fact</i> - `FactPurchase`. Queries are executed by joining dimensions and facts + * in various ways. + * <p/> + * Remote nodes should be started using `ExampleNodeStartup` which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarStarSchemaExample { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Name of replicated cache specified in spring configuration. */ + private val REPL_NAME = "ScalarSnowflakeSchemaExampleReplicated" + + /** Name of partitioned cache specified in spring configuration. */ + private val PART_NAME = "ScalarSnowflakeSchemaExamplePartitioned" + + /** ID generator. */ + private[this] val idGen = Stream.from(System.currentTimeMillis.toInt).iterator + + /** DimStore data. */ + private[this] val dataStore = scala.collection.mutable.Map[JavaInt, DimStore]() + + /** DimProduct data. */ + private[this] val dataProduct = scala.collection.mutable.Map[JavaInt, DimProduct]() + + /** + * Example entry point. No arguments required. + */ + def main(args: Array[String]) { + scalar(CONFIG) { + val dimCache = createCache$[JavaInt, AnyRef](REPL_NAME, CacheMode.REPLICATED, + Seq(classOf[JavaInt], classOf[DimStore], classOf[JavaInt], classOf[DimProduct])) + + try { + val factCache = createCache$[JavaInt, FactPurchase](PART_NAME, + indexedTypes = Seq(classOf[JavaInt], classOf[FactPurchase])) + + try { + populateDimensions(dimCache) + populateFacts(factCache) + + queryStorePurchases() + queryProductPurchases() + } + finally { + factCache.close() + } + } + finally { + dimCache.close() + } + } + } + + /** + * Populate cache with `dimensions` which in our case are + * `DimStore` and `DimProduct` instances. + */ + def populateDimensions(dimCache: IgniteCache[JavaInt, AnyRef]) { + val store1 = new DimStore(idGen.next(), "Store1", "12345", "321 Chilly Dr, NY") + val store2 = new DimStore(idGen.next(), "Store2", "54321", "123 Windy Dr, San Francisco") + + // Populate stores. + dimCache.put(store1.id, store1) + dimCache.put(store2.id, store2) + + dataStore.put(store1.id, store1) + dataStore.put(store2.id, store2) + + for (i <- 1 to 20) { + val product = new DimProduct(idGen.next(), "Product" + i, i + 1, (i + 1) * 10) + + dimCache.put(product.id, product) + + dataProduct.put(product.id, product) + } + } + + /** + * Populate cache with `facts`, which in our case are `FactPurchase` objects. + */ + def populateFacts(factCache: IgniteCache[JavaInt, FactPurchase]) { + for (i <- 1 to 100) { + val store: DimStore = rand(dataStore.values) + val prod: DimProduct = rand(dataProduct.values) + val purchase = new FactPurchase(idGen.next(), prod.id, store.id, i + 1) + + factCache.put(purchase.id, purchase) + } + } + + /** + * Query all purchases made at a specific store. This query uses cross-cache joins + * between `DimStore` objects stored in `replicated` cache and + * `FactPurchase` objects stored in `partitioned` cache. + */ + def queryStorePurchases() { + val factCache = ignite$.cache[JavaInt, FactPurchase](PART_NAME) + + val storePurchases = factCache.sql( + "from \"" + REPL_NAME + "\".DimStore, \"" + PART_NAME + "\".FactPurchase " + + "where DimStore.id=FactPurchase.storeId and DimStore.name=?", "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 `DimStore`, `DimProduct` + * objects stored in `replicated` cache and `FactPurchase` objects + * stored in `partitioned` cache. + */ + private def queryProductPurchases() { + val factCache = ignite$.cache[JavaInt, FactPurchase](PART_NAME) + + // All purchases for certain product made at store2. + // ================================================= + val p1: DimProduct = rand(dataProduct.values) + val p2: DimProduct = rand(dataProduct.values) + val p3: DimProduct = rand(dataProduct.values) + + println("IDs of products [p1=" + p1.id + ", p2=" + p2.id + ", p3=" + p3.id + ']') + + val prodPurchases = factCache.sql( + "from \"" + REPL_NAME + "\".DimStore, \"" + REPL_NAME + "\".DimProduct, \"" + + PART_NAME + "\".FactPurchase " + + "where DimStore.id=FactPurchase.storeId and " + + "DimProduct.id=FactPurchase.productId and " + + "DimStore.name=? and DimProduct.id in(?, ?, ?)", + "Store2", p1.id, p2.id, p3.id) + + 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 def printQueryResults[V](msg: String, res: Iterable[Cache.Entry[JavaInt, V]]) { + println(msg) + + for (e <- res) + println(" " + e.getValue.toString) + } + + /** + * Gets random value from given collection. + * + * @param c Input collection (no `null` and not emtpy). + * @return Random value from the input collection. + */ + def rand[T](c: Iterable[_ <: T]): T = { + val n = ThreadLocalRandom8.current.nextInt(c.size) + + var i = 0 + + for (t <- c) { + if (i < n) + i += 1 + else + return t + } + + throw new ConcurrentModificationException + } +} + +/** + * Represents a product available for purchase. In our `snowflake` schema a `product` + * is a `dimension` and will be cached in `CacheMode#REPLICATED` cache. + * + * @param id Product ID. + * @param name Product name. + * @param price Product list price. + * @param qty Available product quantity. + */ +class DimProduct( + @ScalarCacheQuerySqlField + val id: Int, + val name: String, + @ScalarCacheQuerySqlField + val price: Float, + val qty: Int) { + /** + * `toString` implementation. + */ + override def toString: String = { + val sb = new StringBuilder + + sb.append("DimProduct ") + sb.append("[id=").append(id) + sb.append(", name=").append(name) + sb.append(", price=").append(price) + sb.append(", qty=").append(qty) + sb.append(']') + + sb.toString() + } +} + +/** + * Represents a physical store location. In our `snowflake` schema a `store` + * is a `dimension` and will be cached in `CacheMode#REPLICATED` cache. + * + * @param id Primary key. + * @param name Store name. + * @param zip Zip code. + * @param addr Address. + */ +class DimStore( + @ScalarCacheQuerySqlField + val id: Int, + @ScalarCacheQuerySqlField + val name: String, + val zip: String, + val addr: String) { + /** + * `toString` implementation. + */ + override def toString: String = { + val sb = new StringBuilder + + sb.append("DimStore ") + sb.append("[id=").append(id) + sb.append(", name=").append(name) + sb.append(", zip=").append(zip) + sb.append(", addr=").append(addr) + sb.append(']') + + sb.toString() + } +} + +/** + * Represents a purchase record. In our `snowflake` schema purchase + * is a `fact` and will be cached in larger `CacheMode#PARTITIONED` cache. + * + * @param id Purchase ID. + * @param productId Purchased product ID. + * @param storeId Store ID. + * @param purchasePrice Purchase price. + */ +class FactPurchase( + @ScalarCacheQuerySqlField + val id: Int, + @ScalarCacheQuerySqlField + val productId: Int, + @ScalarCacheQuerySqlField + val storeId: Int, + @ScalarCacheQuerySqlField + val purchasePrice: Float) { + /** + * `toString` implementation. + */ + override def toString: String = { + val sb = new StringBuilder + + sb.append("FactPurchase ") + sb.append("[id=").append(id) + sb.append(", productId=").append(productId) + sb.append(", storeId=").append(storeId) + sb.append(", purchasePrice=").append(purchasePrice) + sb.append(']') + + sb.toString() + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/Person.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/Person.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/Person.scala new file mode 100644 index 0000000..10a8f1b --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/Person.scala @@ -0,0 +1,93 @@ +/* + * + * * 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.scalar.examples.datagrid.store + +import java.lang.Long + +/** + * Person class. + */ +@SerialVersionUID(0L) +class Person() { + /** ID field */ + private[this] var id = 0L + + /** First name field */ + private[this] var firstName: String = null + + /** Last name field */ + private[this] var lastName: String = null + + def this(id: Long, firstName: String, lastName: String) = { + this() + + this.id = id + this.firstName = firstName + this.lastName = lastName + } + + /** + * @return ID field. + */ + def getId = id + + /** + * Update ID field. + * + * @param id New ID field. + */ + def setId(id: Long) { + this.id = id + } + + /** + * @return First name field. + */ + def getFirstName = firstName + + /** + * Update first name field. + * + * @param firstName New first name field. + */ + def setFirstName(firstName: String) { + this.firstName = firstName + } + + /** + * @return Last name field. + */ + def getLastName = lastName + + /** + * Update last name field. + * + * @param lastName New last name field. + */ + def setLastName(lastName: String) { + this.lastName = lastName + } + + /** + * `toString` implementation. + */ + override def toString: String = + "Person [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]" +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/CacheConfig.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/CacheConfig.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/CacheConfig.scala new file mode 100644 index 0000000..1118098 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/CacheConfig.scala @@ -0,0 +1,77 @@ +/* + * + * * 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.scalar.examples.datagrid.store.auto + +import org.apache.ignite.cache.CacheAtomicityMode._ +import org.apache.ignite.cache.store.CacheStore +import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore +import org.apache.ignite.cache.{CacheTypeFieldMetadata, CacheTypeMetadata} +import org.apache.ignite.configuration.CacheConfiguration +import org.apache.ignite.internal.util.scala.impl +import org.apache.ignite.scalar.examples.datagrid.store.Person + +import org.h2.jdbcx.JdbcConnectionPool + +import javax.cache.configuration.Factory +import java.lang.{Long => JavaLong} +import java.sql.Types +import java.util.{Arrays, Collections} + +/** + * Predefined configuration for examples with [[CacheJdbcPojoStore]]. + */ +private[auto] object CacheConfig { + /** + * Configure cache with store. + */ + def jdbcPojoStoreCache(name: String): CacheConfiguration[JavaLong, Person] = { + val cfg = new CacheConfiguration[JavaLong, Person](name) + + cfg.setAtomicityMode(TRANSACTIONAL) + + cfg.setCacheStoreFactory(new Factory[CacheStore[_ >: JavaLong, _ >: Person]] { + @impl def create: CacheStore[_ >: JavaLong, _ >: Person] = { + val store = new CacheJdbcPojoStore[JavaLong, Person] + + store.setDataSource(JdbcConnectionPool.create("jdbc:h2:tcp://localhost/mem:ExampleDb", "sa", "")) + + store + } + }) + + val meta = new CacheTypeMetadata + + meta.setDatabaseTable("PERSON") + meta.setKeyType("java.lang.Long") + meta.setValueType("org.apache.ignite.scalar.examples.datagrid.store.Person") + meta.setKeyFields(Collections.singletonList(new CacheTypeFieldMetadata("ID", Types.BIGINT, "id", classOf[JavaLong]))) + meta.setValueFields(Arrays.asList(new CacheTypeFieldMetadata("ID", Types.BIGINT, "id", classOf[JavaLong]), + new CacheTypeFieldMetadata("FIRST_NAME", Types.VARCHAR, "firstName", classOf[String]), + new CacheTypeFieldMetadata("LAST_NAME", Types.VARCHAR, "lastName", classOf[String]))) + + cfg.setTypeMetadata(Collections.singletonList(meta)) + cfg.setWriteBehindEnabled(true) + cfg.setReadThrough(true) + cfg.setWriteThrough(true) + + cfg + } +} + http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreExample.scala new file mode 100644 index 0000000..60aaac8 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreExample.scala @@ -0,0 +1,94 @@ +/* + * + * * 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.scalar.examples.datagrid.store.auto + +import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore +import org.apache.ignite.examples.ExampleNodeStartup +import org.apache.ignite.examples.datagrid.store.auto.DbH2ServerStartup +import org.apache.ignite.scalar.examples.datagrid.store.Person +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import java.lang.{Long => JavaLong} +import java.util.UUID + +/** + * Demonstrates usage of cache with underlying persistent store configured. + * <p> + * This example uses [[CacheJdbcPojoStore]] as a persistent store. + * <p> + * To start the example, you should: + * <ul> + * <li>Start H2 database TCP server using [[DbH2ServerStartup]].</li> + * <li>Start a few nodes using [[ExampleNodeStartup]] or by starting remote nodes as specified below.</li> + * <li>Start example using [[ScalarCacheAutoStoreExample]].</li> + * </ul> + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheAutoStoreExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheAutoStoreExample.getClass.getSimpleName + + /** Global person ID to use across entire example. */ + private val id = Math.abs(UUID.randomUUID.getLeastSignificantBits) + + scalar(CONFIG) { + println() + println(">>> Cache auto store example started.") + + val cache = createCache$[JavaLong, Person](CacheConfig.jdbcPojoStoreCache(CACHE_NAME)) + + try { + val tx = transaction$() + + try { + var value = cache.get(id) + + println("Read value: " + value) + + value = cache.getAndPut(id, new Person(id, "Isaac", "Newton")) + + println("Overwrote old value: " + value) + + value = cache.get(id) + + println("Read value: " + value) + + tx.commit() + } + finally { + if (tx != null) tx.close() + } + + println("Read value after commit: " + cache.get(id)) + } + finally { + if (cache != null) cache.close() + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreLoadDataExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreLoadDataExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreLoadDataExample.scala new file mode 100644 index 0000000..38d34d6 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/auto/ScalarCacheAutoStoreLoadDataExample.scala @@ -0,0 +1,84 @@ +/* + * + * * 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.scalar.examples.datagrid.store.auto + +import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStore +import org.apache.ignite.examples.datagrid.store.auto.DbH2ServerStartup +import org.apache.ignite.examples.{ExampleNodeStartup, ExamplesUtils} +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import java.lang.{Long => JavaLong} + +/** + * Demonstrates how to load data from database. + * <p> + * This example uses [[CacheJdbcPojoStore]] as a persistent store. + * <p> + * To start the example, you should: + * <ul> + * <li>Start H2 database TCP server using [[DbH2ServerStartup]].</li> + * <li>Start a few nodes using [[ExampleNodeStartup]] or by starting remote nodes as specified below.</li> + * <li>Start example using [[ScalarCacheAutoStoreLoadDataExample]].</li> + * </ul> + * <p> + * Remote nodes should always be started with special configuration file which + * enables P2P class loading: `'ignite.{sh|bat} examples/config/example-ignite.xml'`. + * <p> + * Alternatively you can run [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheAutoStoreLoadDataExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheAutoStoreLoadDataExample.getClass.getSimpleName + + /** Heap size required to run this example. */ + val MIN_MEMORY = 1024 * 1024 * 1024 + + ExamplesUtils.checkMinMemory(MIN_MEMORY) + + scalar(CONFIG) { + println() + println(">>> Cache auto store load data example started.") + + val cacheCfg = CacheConfig.jdbcPojoStoreCache(CACHE_NAME) + + val cache = createCache$(cacheCfg) + + try { + cache.loadCache(null, "java.lang.Long", "select * from PERSON where id <= 3") + + println("Loaded cache entries: " + cache.size()) + + cache.clear() + + cache.loadCache(null) + + println("Loaded cache entries: " + cache.size()) + } + finally { + if (cache != null) + cache.close() + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyPersonStore.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyPersonStore.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyPersonStore.scala new file mode 100644 index 0000000..d12cb27 --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyPersonStore.scala @@ -0,0 +1,101 @@ +/* + * + * * 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.scalar.examples.datagrid.store.dummy + +import org.apache.ignite.Ignite +import org.apache.ignite.cache.store.{CacheStoreAdapter, CacheStoreSession} +import org.apache.ignite.examples.datagrid.store.Person +import org.apache.ignite.lang.IgniteBiInClosure +import org.apache.ignite.resources.{CacheNameResource, CacheStoreSessionResource, IgniteInstanceResource} +import org.apache.ignite.transactions.Transaction + +import org.jetbrains.annotations.Nullable + +import javax.cache.Cache +import java.lang.{Long => JavaLong} +import java.util.concurrent.ConcurrentHashMap + +/** + * Dummy cache store implementation. + */ +class ScalarCacheDummyPersonStore extends CacheStoreAdapter[JavaLong, Person] { + /** Auto-inject ignite instance. */ + @IgniteInstanceResource private var ignite: Ignite = null + + /** Auto-inject cache name. */ + @CacheNameResource private var cacheName: String = null + + /** */ + @CacheStoreSessionResource private var ses: CacheStoreSession = null + + /** Dummy database. */ + private val dummyDB = new ConcurrentHashMap[JavaLong, Person] + + def load(key: JavaLong): Person = { + val tx = transaction + + println(">>> Store load [key=" + key + ", xid=" + (if (tx == null) null else tx.xid) + ']') + + dummyDB.get(key) + } + + def write(entry: Cache.Entry[_ <: JavaLong, _ <: Person]) { + val tx = transaction + + val key = entry.getKey + + val value = entry.getValue + + println(">>> Store put [key=" + key + ", val=" + value + ", xid=" + (if (tx == null) null else tx.xid) + ']') + + dummyDB.put(key, value) + } + + def delete(key: AnyRef) { + val tx = transaction + + println(">>> Store remove [key=" + key + ", xid=" + (if (tx == null) null else tx.xid) + ']') + + dummyDB.remove(key) + } + + override def loadCache(clo: IgniteBiInClosure[JavaLong, Person], args: AnyRef*) { + val cnt = args(0).asInstanceOf[Integer] + + println(">>> Store loadCache for entry count: " + cnt) + + for (i <- 0 until cnt) { + val p = new Person(i, "first-" + i, "last-" + 1) + + if (ignite.affinity(cacheName).isPrimaryOrBackup(ignite.cluster.localNode, p.getId)) { + dummyDB.put(p.getId, p) + + clo.apply(p.getId, p) + } + } + } + + /** + * @return Current transaction. + */ + @Nullable private def transaction: Transaction = { + if (ses != null) ses.transaction else null + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/41a5bf67/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyStoreExample.scala ---------------------------------------------------------------------- diff --git a/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyStoreExample.scala b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyStoreExample.scala new file mode 100644 index 0000000..260497b --- /dev/null +++ b/examples/src/main/scala/org/apache/ignite/scalar/examples/datagrid/store/dummy/ScalarCacheDummyStoreExample.scala @@ -0,0 +1,133 @@ +/* + * + * * 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.scalar.examples.datagrid.store.dummy + +import org.apache.ignite.IgniteCache +import org.apache.ignite.cache.CacheAtomicityMode._ +import org.apache.ignite.configuration.CacheConfiguration +import org.apache.ignite.examples.datagrid.store.Person +import org.apache.ignite.examples.{ExampleNodeStartup, ExamplesUtils} +import org.apache.ignite.scalar.scalar +import org.apache.ignite.scalar.scalar._ + +import javax.cache.configuration.FactoryBuilder +import java.lang.{Long => JavaLong} +import java.util.UUID + +/** + * Demonstrates usage of cache with underlying persistent store configured. + * <p> + * This example uses [[ScalarCacheDummyPersonStore]] as a persistent store. + * <p> + * Remote nodes can be started with [[ExampleNodeStartup]] in another JVM which will + * start node with `examples/config/example-ignite.xml` configuration. + */ +object ScalarCacheDummyStoreExample extends App { + /** Configuration file name. */ + private val CONFIG = "examples/config/example-ignite.xml" + + /** Cache name. */ + private val CACHE_NAME = ScalarCacheDummyStoreExample.getClass.getSimpleName + + /** Heap size required to run this example. */ + val MIN_MEMORY = 1024 * 1024 * 1024 + + /** Number of entries to load. */ + private val ENTRY_COUNT = 100000 + + /** Global person ID to use across entire example. */ + private val id = Math.abs(UUID.randomUUID.getLeastSignificantBits) + + ExamplesUtils.checkMinMemory(MIN_MEMORY) + + scalar(CONFIG) { + println() + println(">>> Cache store example started.") + + val cacheCfg = new CacheConfiguration[JavaLong, Person](CACHE_NAME) + + // Set atomicity as transaction, since we are showing transactions in example. + cacheCfg.setAtomicityMode(TRANSACTIONAL) + + // Configure Dummy store. + cacheCfg.setCacheStoreFactory(FactoryBuilder.factoryOf(classOf[ScalarCacheDummyPersonStore])) + + cacheCfg.setReadThrough(true) + cacheCfg.setWriteThrough(true) + + val cache = createCache$[JavaLong, Person](cacheCfg) + + try { + loadCache(cache) + + executeTransaction(cache) + } + finally { + if (cache != null) + cache.close() + } + } + + /** + * Makes initial cache loading. + * + * @param cache Cache to load. + */ + private def loadCache(cache: IgniteCache[JavaLong, Person]) { + val start = System.currentTimeMillis + + cache.loadCache(null, Integer.valueOf(ENTRY_COUNT)) + + val end = System.currentTimeMillis + + 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 def executeTransaction(cache: IgniteCache[JavaLong, Person]) { + val tx = transaction$() + + try { + var value = cache.get(id) + + println("Read value: " + value) + + value = cache.getAndPut(id, new Person(id, "Isaac", "Newton")) + + println("Overwrote old value: " + value) + + value = cache.get(id) + + println("Read value: " + value) + + tx.commit() + } + finally { + if (tx != null) + tx.close() + } + + println("Read value after commit: " + cache.get(id)) + } +}