You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by pi...@apache.org on 2018/03/06 18:35:37 UTC

[geode-examples] branch develop updated: GEODE-4233: Add an example for transactions. (#51)

This is an automated email from the ASF dual-hosted git repository.

pivotalsarge pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-examples.git


The following commit(s) were added to refs/heads/develop by this push:
     new 5e6e4f5  GEODE-4233: Add an example for transactions. (#51)
5e6e4f5 is described below

commit 5e6e4f5dd054f7ca8ffcff859307bbab390bf16b
Author: Michael "Sarge" Dodge <md...@pivotal.io>
AuthorDate: Tue Mar 6 10:35:35 2018 -0800

    GEODE-4233: Add an example for transactions. (#51)
    
    * GEODE-4233: Add an example for transactions.
    
    * GEODE-4233: Address review comments.
    
    * GEODE-4233: Fix classpath to include example JAR.
    
    * GEODE-4440: Create an example that demonstrates OQL compact range indexes. (#48)
    
    * GEODE-4440: Create an example that demonstrates OQL compact range indexes.
    
    * GEODE-4440: Address review comments.
    
    * GEODE-4440: Address review comment.
    
    * GEODE-4646: Add build-specific instructions. (#49)
    
    * GEODE-4646: Add build-specific instructions.
    
    * GEODE-4646: Fix references to gradle to use the wrapper.
    
    * GEODE-4666: Ensure a clean working environment for examples. (#52)
    
    * Add both preliminary check and delay after teardown.
    
    * GEODE-4233: Address review comment.
---
 README.md                                          |   3 +-
 settings.gradle                                    |   1 +
 transaction/README.md                              |  60 +++++++++++
 transaction/scripts/start.gfsh                     |  24 +++++
 transaction/scripts/stop.gfsh                      |  19 ++++
 .../apache/geode_examples/transaction/Example.java | 111 +++++++++++++++++++++
 .../geode_examples/transaction/Incrementer.java    |  70 +++++++++++++
 7 files changed, 287 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 2aad532..7718197 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ tutorial.
 *  [Cache Listeners](listener/README.md)
 *  [Async Event Queues & Async Event Listeners](async/README.md)
 *  Continuous Querying
-*  Transactions
+*  [Transaction](transaction/README.md)
 *  [Eviction](eviction/README.md)
 *  [Expiration](expiration/README.md)
 *  Overflow
@@ -85,6 +85,7 @@ tutorial.
 
 ### Advanced
 
+*  [Lucene Spatial Indexing](luceneSpatial/README.md)
 *  WAN Gateway
 *  Durable subscriptions
 *  Delta propagation
diff --git a/settings.gradle b/settings.gradle
index d23bb7e..86ebb89 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,3 +33,4 @@ include 'eviction'
 include 'serialization'
 include 'expiration'
 include 'indexes'
+include 'transaction'
diff --git a/transaction/README.md b/transaction/README.md
new file mode 100644
index 0000000..c6b28c3
--- /dev/null
+++ b/transaction/README.md
@@ -0,0 +1,60 @@
+<!--
+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.
+-->
+
+# Geode Transaction Example
+
+This is a simple example that demonstrates the use of [transactions](https://geode.apache.org/docs/guide/11/developing/transactions/working_with_transactions.html)
+to protect consistency during concurrent access and modification of data. Since a region may
+configured across multiple servers and multiple clients may interact with that region independent of
+each other, data integrity relies on synchronization of modifications between all actors.
+
+An example of how data can become inconsistent during concurrent interaction is as follows:
+ 1. Client A gets the value of a key.
+ 2. Client B gets the value of the same key.
+ 3. Client A puts a new value for the key based upon the original value.
+ 4. Client B puts a different new value for the key based upon the original value.
+The final value for that key is based upon the original value, _not_ the updated value from Client
+A. For the final value to contain all the calculations from both clients, both the access and the
+modification of the value would need to happen as an atomic action across the region.
+
+This example starts five child processes, each of which tries one thousand times to get the current
+value of a counter, increment that value, and the put the incremented value back into the region.
+To protect data consistency, the incrementing is abandoned and retried if another child has already
+incremented the value _or_ if another child is simultaenously trying to increment the value. This
+example, which should take about a dozen seconds, reports the final value of the counter to show
+that all of the children's increments were consistently applied.
+
+This example assumes you have installed Java and Geode.
+
+## Steps
+
+1. From the `geode-examples/transaction` directory, build the example and
+   run unit tests.
+
+        $ ../gradlew build
+
+2. Next start a locator, start a server, and create a region.
+
+        $ gfsh run --file=scripts/start.gfsh
+
+3. Run the example to demonstrate transactions.
+
+        $ ../gradlew run
+
+4. Shut down the system.
+
+        $ gfsh run --file=scripts/stop.gfsh
diff --git a/transaction/scripts/start.gfsh b/transaction/scripts/start.gfsh
new file mode 100755
index 0000000..94e14a5
--- /dev/null
+++ b/transaction/scripts/start.gfsh
@@ -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.
+#
+
+start locator --name=locator --bind-address=127.0.0.1
+start server --name=server1 --locators=127.0.0.1[10334] --server-port=0 --classpath=../build/classes/main
+start server --name=server2 --locators=127.0.0.1[10334] --server-port=0 --classpath=../build/classes/main
+list members
+
+create region --name=example-region --type=REPLICATE --skip-if-exists=true
+describe region --name=example-region
diff --git a/transaction/scripts/stop.gfsh b/transaction/scripts/stop.gfsh
new file mode 100755
index 0000000..15cd93c
--- /dev/null
+++ b/transaction/scripts/stop.gfsh
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+connect --locator=127.0.0.1[10334]
+shutdown --include-locators=true
diff --git a/transaction/src/main/java/org/apache/geode_examples/transaction/Example.java b/transaction/src/main/java/org/apache/geode_examples/transaction/Example.java
new file mode 100644
index 0000000..64428e4
--- /dev/null
+++ b/transaction/src/main/java/org/apache/geode_examples/transaction/Example.java
@@ -0,0 +1,111 @@
+/*
+ * 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.geode_examples.transaction;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.ClientRegionFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Example {
+  public static final int INCREMENTS = 1000;
+
+  public static final String REGION_NAME = "example-region";
+
+  public static final String KEY = "counter";
+
+  final Region<String, Integer> region;
+
+  final Map<Integer, Process> children = new HashMap<>();
+
+  static String constructJVMPath() {
+    StringBuilder builder = new StringBuilder();
+    builder.append(System.getProperty("java.home"));
+    builder.append(File.separator);
+    builder.append("bin");
+    builder.append(File.separator);
+    builder.append("java");
+    if (System.getProperty("os.name").toLowerCase().contains("win")) {
+      builder.append("w.exe");
+    }
+    return builder.toString();
+  }
+
+  public static void main(String[] args) {
+    // connect to the locator using default port 10334
+    ClientCache cache = new ClientCacheFactory().addPoolLocator("127.0.0.1", 10334)
+        .set("log-level", "WARN").create();
+
+    // create a local region that matches the server region
+    ClientRegionFactory<String, Integer> clientRegionFactory =
+        cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
+    Region<String, Integer> region = clientRegionFactory.create(REGION_NAME);
+
+    Example example = new Example(region);
+    example.initializeEntry();
+    example.executeChildProcesses(5);
+
+    cache.close();
+  }
+
+  Example(Region<String, Integer> region) {
+    this.region = region;
+  }
+
+  void executeChildProcess(int id) {
+    String[] command = new String[5];
+    command[0] = constructJVMPath();
+    command[1] = "-classpath";
+    command[2] = System.getProperty("java.class.path") + ":build/libs/transaction.jar";
+    command[3] = "org.apache.geode_examples.transaction.Incrementer";
+    command[4] = Integer.toString(id);
+    try {
+      children.put(id, Runtime.getRuntime().exec(command));
+      System.out.println("Executed child " + id);
+    } catch (IOException ioe) {
+      ioe.printStackTrace();
+    }
+  }
+
+  void executeChildProcesses(int numberOfIncrementers) {
+    System.out.println("Expected value of counter: " + (numberOfIncrementers * INCREMENTS));
+
+    for (int i = 0; i < numberOfIncrementers; ++i) {
+      executeChildProcess(i + 1);
+    }
+
+    for (Map.Entry<Integer, Process> child : children.entrySet()) {
+      System.out.println("Waiting for " + child.getKey() + "...");
+      try {
+        child.getValue().waitFor();
+        System.out.println("Reaped child " + child.getKey());
+      } catch (InterruptedException ie) {
+        ie.printStackTrace();
+      }
+    }
+
+    System.out.println("Actual value of counter:   " + region.get(KEY));
+  }
+
+  void initializeEntry() {
+    region.put(KEY, 0);
+  }
+}
diff --git a/transaction/src/main/java/org/apache/geode_examples/transaction/Incrementer.java b/transaction/src/main/java/org/apache/geode_examples/transaction/Incrementer.java
new file mode 100644
index 0000000..36e8497
--- /dev/null
+++ b/transaction/src/main/java/org/apache/geode_examples/transaction/Incrementer.java
@@ -0,0 +1,70 @@
+/*
+ * 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.geode_examples.transaction;
+
+import org.apache.geode.cache.CacheTransactionManager;
+import org.apache.geode.cache.CommitConflictException;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.client.ClientCache;
+import org.apache.geode.cache.client.ClientCacheFactory;
+import org.apache.geode.cache.client.ClientRegionFactory;
+import org.apache.geode.cache.client.ClientRegionShortcut;
+
+public class Incrementer {
+  final int id;
+  final ClientCache cache;
+  final Region<String, Integer> region;
+
+  Incrementer(int id, ClientCache cache, Region<String, Integer> region) {
+    this.id = id;
+    this.cache = cache;
+    this.region = region;
+  }
+
+  public static void main(String[] args) {
+    // connect to the locator using default port 10334
+    ClientCache cache = new ClientCacheFactory().addPoolLocator("127.0.0.1", 10334)
+        .set("log-level", "WARN").create();
+
+    // create a local region that matches the server region
+    ClientRegionFactory<String, Integer> clientRegionFactory =
+        cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
+    Region<String, Integer> region = clientRegionFactory.create(Example.REGION_NAME);
+
+    Incrementer incrementer = new Incrementer(Integer.parseInt(args[0]), cache, region);
+    incrementer.incrementEntry();
+
+    cache.close();
+  }
+
+  void incrementEntry() {
+    CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager();
+    for (int i = 0; i < Example.INCREMENTS; ++i) {
+      boolean incremented = false;
+      while (!incremented) {
+        try {
+          cacheTransactionManager.begin();
+          final Integer oldValue = region.get(Example.KEY);
+          final Integer newValue = oldValue + 1;
+          region.put(Example.KEY, newValue);
+          cacheTransactionManager.commit();
+          incremented = true;
+        } catch (CommitConflictException cce) {
+          // Do nothing.
+        }
+      }
+    }
+  }
+}

-- 
To stop receiving notification emails like this one, please contact
pivotalsarge@apache.org.